Merge master.kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc
authorLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 8 Feb 2007 18:04:20 +0000 (10:04 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Thu, 8 Feb 2007 18:04:20 +0000 (10:04 -0800)
* master.kernel.org:/pub/scm/linux/kernel/git/paulus/powerpc: (116 commits)
  [POWERPC] Add export of vgacon_remap_base
  [POWERPC] Remove bogus comment about page_is_ram
  [POWERPC] windfarm: don't die on suspend thread signal
  [POWERPC] Fix comment in kernel/irq.c
  [POWERPC] ppc: Fix booke watchdog initialization
  [POWERPC] PPC: Use ARRAY_SIZE macro when appropriate
  [POWERPC] Use ARRAY_SIZE macro when appropriate
  [POWERPC] Fix ppc64's writing to struct file_operations
  [POWERPC] ppc: use syslog macro for the printk log level
  [POWERPC] ppc: cs4218_tdm remove extra brace
  [POWERPC] Add mpc52xx/lite5200 PCI support
  [POWERPC] Only use H_BULK_REMOVE if the firmware supports it
  [POWERPC] Fixup error handling when emulating a floating point instruction
  [POWERPC] Enable interrupts if we are doing fp math emulation
  [POWERPC] Added kprobes support to ppc32
  [POWERPC] Make pSeries use the H_BULK_REMOVE hypervisor call
  [POWERPC] Clear RI bit in MSR before restoring r13 when returning to userspace
  [POWERPC] Fix performance monitor exception
  [POWERPC] Compile fixes for arch/powerpc dcr code
  [POWERPC] Maple: use mmio nvram
  ...

1069 files changed:
Documentation/HOWTO
Documentation/feature-removal-schedule.txt
Documentation/s390/Debugging390.txt
Documentation/usb/proc_usb_info.txt
Documentation/usb/usbmon.txt
Documentation/video-output.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/alpha/kernel/pci.c
arch/i386/defconfig
arch/i386/kernel/acpi/boot.c
arch/i386/kernel/acpi/earlyquirk.c
arch/i386/kernel/cpu/cpufreq/longhaul.c
arch/i386/kernel/io_apic.c
arch/i386/kernel/mpparse.c
arch/i386/kernel/srat.c
arch/i386/mach-es7000/es7000.h
arch/i386/mach-es7000/es7000plat.c
arch/i386/pci/mmconfig.c
arch/ia64/Kconfig
arch/ia64/hp/common/hwsw_iommu.c
arch/ia64/kernel/acpi.c
arch/ia64/kernel/crash.c
arch/ia64/kernel/crash_dump.c
arch/ia64/kernel/efi.c
arch/ia64/kernel/entry.S
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/machine_kexec.c
arch/ia64/kernel/msi_ia64.c
arch/ia64/kernel/process.c
arch/ia64/kernel/ptrace.c
arch/ia64/kernel/setup.c
arch/ia64/kernel/vmlinux.lds.S
arch/ia64/mm/contig.c
arch/ia64/mm/discontig.c
arch/ia64/mm/init.c
arch/ia64/sn/kernel/huberror.c
arch/ia64/sn/kernel/io_acpi_init.c
arch/ia64/sn/kernel/io_common.c
arch/ia64/sn/kernel/io_init.c
arch/ia64/sn/kernel/iomv.c
arch/ia64/sn/kernel/msi_sn.c
arch/ia64/sn/pci/pcibr/pcibr_provider.c
arch/mips/Kconfig
arch/mips/Kconfig.debug
arch/mips/arc/identify.c
arch/mips/arc/memory.c
arch/mips/au1000/common/irq.c
arch/mips/au1000/common/pci.c
arch/mips/au1000/common/prom.c
arch/mips/au1000/common/setup.c
arch/mips/au1000/pb1100/board_setup.c
arch/mips/au1000/pb1200/irqmap.c
arch/mips/basler/excite/excite_irq.c
arch/mips/cobalt/irq.c
arch/mips/cobalt/setup.c
arch/mips/ddb5xxx/common/prom.c
arch/mips/ddb5xxx/ddb5477/irq.c
arch/mips/ddb5xxx/ddb5477/irq_5477.c
arch/mips/dec/ioasic-irq.c
arch/mips/dec/kn02-irq.c
arch/mips/dec/prom/memory.c
arch/mips/dec/setup.c
arch/mips/emma2rh/common/irq_emma2rh.c
arch/mips/emma2rh/markeins/irq.c
arch/mips/emma2rh/markeins/irq_markeins.c
arch/mips/gt64120/ev64120/irq.c
arch/mips/gt64120/ev64120/setup.c
arch/mips/gt64120/momenco_ocelot/dbg_io.c
arch/mips/gt64120/momenco_ocelot/irq.c
arch/mips/gt64120/momenco_ocelot/prom.c
arch/mips/gt64120/wrppmc/irq.c
arch/mips/gt64120/wrppmc/setup.c
arch/mips/jazz/irq.c
arch/mips/jmr3927/common/prom.c
arch/mips/jmr3927/rbhma3100/irq.c
arch/mips/jmr3927/rbhma3100/setup.c
arch/mips/kernel/asm-offsets.c
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/gdb-stub.c
arch/mips/kernel/head.S
arch/mips/kernel/i8259.c
arch/mips/kernel/irixelf.c
arch/mips/kernel/irq-msc01.c
arch/mips/kernel/irq-mv6434x.c
arch/mips/kernel/irq-rm7000.c
arch/mips/kernel/irq-rm9000.c
arch/mips/kernel/irq_cpu.c
arch/mips/kernel/linux32.c
arch/mips/kernel/mips-mt.c
arch/mips/kernel/proc.c
arch/mips/kernel/process.c
arch/mips/kernel/r4k_fpu.S
arch/mips/kernel/rtlx.c
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/setup.c
arch/mips/kernel/signal.c
arch/mips/kernel/signal_n32.c
arch/mips/kernel/smp-mt.c
arch/mips/kernel/smtc.c
arch/mips/kernel/sysirix.c
arch/mips/kernel/vpe.c
arch/mips/lasat/interrupt.c
arch/mips/lasat/prom.c
arch/mips/lib-32/Makefile
arch/mips/lib-32/memset.S [deleted file]
arch/mips/lib-64/Makefile
arch/mips/lib-64/memset.S [deleted file]
arch/mips/lib/Makefile
arch/mips/lib/memset.S [new file with mode: 0644]
arch/mips/lib/uncached.c
arch/mips/mips-boards/atlas/atlas_int.c
arch/mips/mips-boards/generic/memory.c
arch/mips/mips-boards/malta/malta_int.c
arch/mips/mips-boards/sead/sead_int.c
arch/mips/mips-boards/sim/sim_int.c
arch/mips/mips-boards/sim/sim_mem.c
arch/mips/mm/init.c
arch/mips/momentum/jaguar_atx/Makefile
arch/mips/momentum/jaguar_atx/irq.c
arch/mips/momentum/jaguar_atx/jaguar_atx_fpga.h
arch/mips/momentum/jaguar_atx/platform.c [new file with mode: 0644]
arch/mips/momentum/jaguar_atx/prom.c
arch/mips/momentum/ocelot_3/irq.c
arch/mips/momentum/ocelot_3/prom.c
arch/mips/momentum/ocelot_c/cpci-irq.c
arch/mips/momentum/ocelot_c/dbg_io.c
arch/mips/momentum/ocelot_c/irq.c
arch/mips/momentum/ocelot_c/prom.c
arch/mips/momentum/ocelot_c/uart-irq.c
arch/mips/momentum/ocelot_g/dbg_io.c
arch/mips/momentum/ocelot_g/irq.c
arch/mips/momentum/ocelot_g/prom.c
arch/mips/oprofile/Kconfig
arch/mips/pci/fixup-vr4133.c
arch/mips/philips/pnx8550/common/int.c
arch/mips/philips/pnx8550/common/prom.c
arch/mips/pmc-sierra/yosemite/dbg_io.c
arch/mips/pmc-sierra/yosemite/irq.c
arch/mips/pmc-sierra/yosemite/prom.c
arch/mips/pmc-sierra/yosemite/setup.c
arch/mips/qemu/q-mem.c
arch/mips/sgi-ip22/ip22-eisa.c
arch/mips/sgi-ip22/ip22-int.c
arch/mips/sgi-ip22/ip22-mc.c
arch/mips/sgi-ip27/ip27-irq.c
arch/mips/sgi-ip27/ip27-memory.c
arch/mips/sgi-ip27/ip27-timer.c
arch/mips/sgi-ip32/ip32-irq.c
arch/mips/sgi-ip32/ip32-memory.c
arch/mips/sibyte/bcm1480/irq.c
arch/mips/sibyte/cfe/setup.c
arch/mips/sibyte/sb1250/irq.c
arch/mips/sibyte/sb1250/prom.c
arch/mips/sni/irq.c
arch/mips/sni/sniprom.c
arch/mips/tx4927/common/tx4927_irq.c
arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_irq.c
arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_prom.c
arch/mips/tx4938/common/irq.c
arch/mips/tx4938/toshiba_rbtx4938/irq.c
arch/mips/tx4938/toshiba_rbtx4938/prom.c
arch/mips/vr41xx/common/icu.c
arch/mips/vr41xx/common/init.c
arch/mips/vr41xx/common/irq.c
arch/mips/vr41xx/nec-cmbvr4133/irq.c
arch/powerpc/Kconfig
arch/powerpc/kernel/pci_64.c
arch/s390/Kconfig
arch/s390/appldata/appldata_base.c
arch/s390/appldata/appldata_mem.c
arch/s390/appldata/appldata_net_sum.c
arch/s390/crypto/Kconfig [new file with mode: 0644]
arch/s390/crypto/Makefile
arch/s390/crypto/aes_s390.c
arch/s390/crypto/crypt_s390.h
arch/s390/crypto/crypt_s390_query.c [deleted file]
arch/s390/crypto/des_check_key.c
arch/s390/crypto/des_s390.c
arch/s390/crypto/prng.c [new file with mode: 0644]
arch/s390/crypto/sha1_s390.c
arch/s390/crypto/sha256_s390.c
arch/s390/defconfig
arch/s390/hypfs/Makefile
arch/s390/hypfs/hypfs.h
arch/s390/hypfs/hypfs_diag.h [deleted file]
arch/s390/hypfs/hypfs_vm.c [new file with mode: 0644]
arch/s390/hypfs/inode.c
arch/s390/kernel/Makefile
arch/s390/kernel/base.S [new file with mode: 0644]
arch/s390/kernel/binfmt_elf32.c
arch/s390/kernel/compat_exec_domain.c
arch/s390/kernel/compat_linux.c
arch/s390/kernel/compat_linux.h
arch/s390/kernel/compat_signal.c
arch/s390/kernel/cpcmd.c
arch/s390/kernel/crash.c
arch/s390/kernel/debug.c
arch/s390/kernel/early.c [new file with mode: 0644]
arch/s390/kernel/ebcdic.c
arch/s390/kernel/head31.S
arch/s390/kernel/head64.S
arch/s390/kernel/ipl.c
arch/s390/kernel/irq.c
arch/s390/kernel/kprobes.c
arch/s390/kernel/machine_kexec.c
arch/s390/kernel/module.c
arch/s390/kernel/process.c
arch/s390/kernel/profile.c [deleted file]
arch/s390/kernel/ptrace.c
arch/s390/kernel/reset.S [deleted file]
arch/s390/kernel/s390_ext.c
arch/s390/kernel/setup.c
arch/s390/kernel/signal.c
arch/s390/kernel/smp.c
arch/s390/kernel/stacktrace.c
arch/s390/kernel/time.c
arch/s390/kernel/traps.c
arch/s390/kernel/vmlinux.lds.S
arch/s390/kernel/vtime.c
arch/s390/lib/Makefile
arch/s390/lib/delay.c
arch/s390/lib/qrnnd.S [new file with mode: 0644]
arch/s390/lib/uaccess.h [new file with mode: 0644]
arch/s390/lib/uaccess_mvcos.c
arch/s390/lib/uaccess_pt.c
arch/s390/lib/uaccess_std.c
arch/s390/math-emu/Makefile
arch/s390/math-emu/math.c
arch/s390/math-emu/qrnnd.S [deleted file]
arch/s390/math-emu/sfp-util.h [deleted file]
arch/s390/mm/cmm.c
arch/s390/mm/extmem.c
arch/s390/mm/fault.c
arch/s390/mm/init.c
arch/s390/mm/vmem.c
arch/x86_64/kernel/early-quirks.c
arch/x86_64/kernel/genapic.c
arch/x86_64/kernel/io_apic.c
arch/x86_64/kernel/mpparse.c
arch/x86_64/kernel/pci-swiotlb.c
arch/x86_64/kernel/time.c
arch/x86_64/mm/srat.c
arch/x86_64/pci/mmconfig.c
crypto/Kconfig
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/asus_acpi.c
drivers/acpi/battery.c
drivers/acpi/bay.c [new file with mode: 0644]
drivers/acpi/blacklist.c
drivers/acpi/bus.c
drivers/acpi/button.c
drivers/acpi/container.c
drivers/acpi/debug.c
drivers/acpi/dispatcher/dsfield.c
drivers/acpi/dispatcher/dsinit.c
drivers/acpi/dispatcher/dsmethod.c
drivers/acpi/dispatcher/dsmthdat.c
drivers/acpi/dispatcher/dsobject.c
drivers/acpi/dispatcher/dsopcode.c
drivers/acpi/dispatcher/dsutils.c
drivers/acpi/dispatcher/dswexec.c
drivers/acpi/dispatcher/dswload.c
drivers/acpi/dispatcher/dswscope.c
drivers/acpi/dispatcher/dswstate.c
drivers/acpi/dock.c
drivers/acpi/ec.c
drivers/acpi/events/evevent.c
drivers/acpi/events/evgpe.c
drivers/acpi/events/evgpeblk.c
drivers/acpi/events/evmisc.c
drivers/acpi/events/evregion.c
drivers/acpi/events/evrgnini.c
drivers/acpi/events/evsci.c
drivers/acpi/events/evxface.c
drivers/acpi/events/evxfevnt.c
drivers/acpi/events/evxfregn.c
drivers/acpi/executer/exconfig.c
drivers/acpi/executer/exconvrt.c
drivers/acpi/executer/excreate.c
drivers/acpi/executer/exdump.c
drivers/acpi/executer/exfield.c
drivers/acpi/executer/exfldio.c
drivers/acpi/executer/exmisc.c
drivers/acpi/executer/exmutex.c
drivers/acpi/executer/exnames.c
drivers/acpi/executer/exoparg1.c
drivers/acpi/executer/exoparg2.c
drivers/acpi/executer/exoparg3.c
drivers/acpi/executer/exoparg6.c
drivers/acpi/executer/exprep.c
drivers/acpi/executer/exregion.c
drivers/acpi/executer/exresnte.c
drivers/acpi/executer/exresolv.c
drivers/acpi/executer/exresop.c
drivers/acpi/executer/exstore.c
drivers/acpi/executer/exstoren.c
drivers/acpi/executer/exstorob.c
drivers/acpi/executer/exsystem.c
drivers/acpi/executer/exutils.c
drivers/acpi/fan.c
drivers/acpi/glue.c
drivers/acpi/hardware/hwacpi.c
drivers/acpi/hardware/hwgpe.c
drivers/acpi/hardware/hwregs.c
drivers/acpi/hardware/hwsleep.c
drivers/acpi/hardware/hwtimer.c
drivers/acpi/motherboard.c [deleted file]
drivers/acpi/namespace/nsaccess.c
drivers/acpi/namespace/nsalloc.c
drivers/acpi/namespace/nsdump.c
drivers/acpi/namespace/nsdumpdv.c
drivers/acpi/namespace/nseval.c
drivers/acpi/namespace/nsinit.c
drivers/acpi/namespace/nsload.c
drivers/acpi/namespace/nsnames.c
drivers/acpi/namespace/nsobject.c
drivers/acpi/namespace/nsparse.c
drivers/acpi/namespace/nssearch.c
drivers/acpi/namespace/nsutils.c
drivers/acpi/namespace/nswalk.c
drivers/acpi/namespace/nsxfeval.c
drivers/acpi/namespace/nsxfname.c
drivers/acpi/namespace/nsxfobj.c
drivers/acpi/numa.c
drivers/acpi/osl.c
drivers/acpi/parser/psargs.c
drivers/acpi/parser/psloop.c
drivers/acpi/parser/psopcode.c
drivers/acpi/parser/psparse.c
drivers/acpi/parser/psscope.c
drivers/acpi/parser/pstree.c
drivers/acpi/parser/psutils.c
drivers/acpi/parser/pswalk.c
drivers/acpi/parser/psxface.c
drivers/acpi/pci_link.c
drivers/acpi/pci_root.c
drivers/acpi/processor_core.c
drivers/acpi/processor_idle.c
drivers/acpi/processor_perflib.c
drivers/acpi/processor_throttling.c
drivers/acpi/resources/rsaddr.c
drivers/acpi/resources/rscalc.c
drivers/acpi/resources/rscreate.c
drivers/acpi/resources/rsdump.c
drivers/acpi/resources/rsinfo.c
drivers/acpi/resources/rsio.c
drivers/acpi/resources/rsirq.c
drivers/acpi/resources/rslist.c
drivers/acpi/resources/rsmemory.c
drivers/acpi/resources/rsmisc.c
drivers/acpi/resources/rsutils.c
drivers/acpi/resources/rsxface.c
drivers/acpi/scan.c
drivers/acpi/sleep/proc.c
drivers/acpi/system.c
drivers/acpi/tables.c
drivers/acpi/tables/Makefile
drivers/acpi/tables/tbconvrt.c [deleted file]
drivers/acpi/tables/tbfadt.c [new file with mode: 0644]
drivers/acpi/tables/tbfind.c [new file with mode: 0644]
drivers/acpi/tables/tbget.c [deleted file]
drivers/acpi/tables/tbgetall.c [deleted file]
drivers/acpi/tables/tbinstal.c
drivers/acpi/tables/tbrsdt.c [deleted file]
drivers/acpi/tables/tbutils.c
drivers/acpi/tables/tbxface.c
drivers/acpi/tables/tbxfroot.c
drivers/acpi/thermal.c
drivers/acpi/utilities/utalloc.c
drivers/acpi/utilities/utcache.c
drivers/acpi/utilities/utcopy.c
drivers/acpi/utilities/utdebug.c
drivers/acpi/utilities/utdelete.c
drivers/acpi/utilities/uteval.c
drivers/acpi/utilities/utglobal.c
drivers/acpi/utilities/utinit.c
drivers/acpi/utilities/utmath.c
drivers/acpi/utilities/utmisc.c
drivers/acpi/utilities/utmutex.c
drivers/acpi/utilities/utobject.c
drivers/acpi/utilities/utresrc.c
drivers/acpi/utilities/utstate.c
drivers/acpi/utilities/utxface.c
drivers/acpi/video.c
drivers/base/class.c
drivers/base/core.c
drivers/base/dd.c
drivers/base/firmware_class.c
drivers/base/platform.c
drivers/char/drm/drmP.h
drivers/char/drm/drm_bufs.c
drivers/char/drm/drm_memory.c
drivers/char/drm/drm_memory.h
drivers/char/drm/drm_memory_debug.h
drivers/char/drm/drm_mm.c
drivers/char/drm/drm_pciids.h
drivers/char/drm/drm_proc.c
drivers/char/drm/drm_sman.c
drivers/char/drm/drm_vm.c
drivers/char/drm/i810_dma.c
drivers/char/drm/i810_drv.h
drivers/char/drm/i830_dma.c
drivers/char/drm/i830_drv.h
drivers/char/drm/via_dma.c
drivers/char/drm/via_dmablit.c
drivers/char/drm/via_drv.h
drivers/char/drm/via_irq.c
drivers/char/drm/via_map.c
drivers/char/drm/via_verifier.c
drivers/char/drm/via_verifier.h
drivers/char/ipmi/ipmi_si_intf.c
drivers/char/tpm/tpm_bios.c
drivers/crypto/Kconfig
drivers/firmware/pcdp.c
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-core.c
drivers/hid/hid-debug.c [new file with mode: 0644]
drivers/hid/hid-input.c
drivers/i2c/chips/isp1301_omap.c
drivers/ide/Kconfig
drivers/ide/Makefile
drivers/ide/ide-acpi.c [new file with mode: 0644]
drivers/ide/ide-probe.c
drivers/ide/ide.c
drivers/ide/pci/Makefile
drivers/ide/pci/delkin_cb.c [new file with mode: 0644]
drivers/ide/pci/hpt366.c
drivers/ide/pci/it8213.c [new file with mode: 0644]
drivers/ide/pci/pdc202xx_new.c
drivers/ide/pci/pdc202xx_old.c
drivers/ide/pci/piix.c
drivers/ide/pci/slc90e66.c
drivers/ide/pci/tc86c001.c [new file with mode: 0644]
drivers/ide/setup-pci.c
drivers/infiniband/core/addr.c
drivers/infiniband/core/mad.c
drivers/infiniband/core/uverbs_cmd.c
drivers/infiniband/hw/amso1100/c2_cq.c
drivers/infiniband/hw/ehca/ehca_classes.h
drivers/infiniband/hw/ehca/ehca_cq.c
drivers/infiniband/hw/ehca/ehca_iverbs.h
drivers/infiniband/hw/ehca/ehca_main.c
drivers/infiniband/hw/ehca/ehca_qp.c
drivers/infiniband/hw/ehca/ehca_reqs.c
drivers/infiniband/hw/ehca/ehca_uverbs.c
drivers/infiniband/hw/ipath/ipath_qp.c
drivers/infiniband/hw/ipath/ipath_rc.c
drivers/infiniband/hw/ipath/ipath_ruc.c
drivers/infiniband/hw/ipath/ipath_uc.c
drivers/infiniband/hw/ipath/ipath_ud.c
drivers/infiniband/hw/mthca/mthca_cmd.c
drivers/infiniband/hw/mthca/mthca_cq.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/infiniband/ulp/ipoib/ipoib_vlan.c
drivers/infiniband/ulp/srp/ib_srp.c
drivers/infiniband/ulp/srp/ib_srp.h
drivers/input/serio/serio.c
drivers/media/video/zc0301/zc0301_sensor.h
drivers/misc/Kconfig
drivers/misc/Makefile
drivers/misc/asus-laptop.c [new file with mode: 0644]
drivers/misc/tifm_7xx1.c
drivers/misc/tifm_core.c
drivers/mmc/at91_mci.c
drivers/mmc/au1xmmc.c
drivers/mmc/imxmmc.c
drivers/mmc/mmc.c
drivers/mmc/mmc_block.c
drivers/mmc/mmc_queue.c
drivers/mmc/mmc_sysfs.c
drivers/mmc/mmci.c
drivers/mmc/omap.c
drivers/mmc/pxamci.c
drivers/mmc/sdhci.c
drivers/mmc/sdhci.h
drivers/mmc/tifm_sd.c
drivers/mmc/wbsd.c
drivers/mmc/wbsd.h
drivers/net/3c59x.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/Space.c
drivers/net/amd8111e.c
drivers/net/arm/at91_ether.c
drivers/net/arm/etherh.c
drivers/net/b44.c
drivers/net/b44.h
drivers/net/bmac.c
drivers/net/bnx2.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bond_sysfs.c
drivers/net/bonding/bonding.h
drivers/net/chelsio/common.h
drivers/net/chelsio/cpl5_cmd.h
drivers/net/chelsio/cxgb2.c
drivers/net/chelsio/elmer0.h
drivers/net/chelsio/espi.c
drivers/net/chelsio/fpga_defs.h
drivers/net/chelsio/gmac.h
drivers/net/chelsio/ixf1010.c
drivers/net/chelsio/mv88e1xxx.c
drivers/net/chelsio/my3126.c
drivers/net/chelsio/pm3393.c
drivers/net/chelsio/sge.c
drivers/net/chelsio/subr.c
drivers/net/chelsio/tp.c
drivers/net/chelsio/vsc7326.c
drivers/net/chelsio/vsc7326_reg.h
drivers/net/chelsio/vsc8244.c
drivers/net/cxgb3/Makefile [new file with mode: 0644]
drivers/net/cxgb3/adapter.h [new file with mode: 0644]
drivers/net/cxgb3/ael1002.c [new file with mode: 0644]
drivers/net/cxgb3/common.h [new file with mode: 0644]
drivers/net/cxgb3/cxgb3_ctl_defs.h [new file with mode: 0644]
drivers/net/cxgb3/cxgb3_defs.h [new file with mode: 0644]
drivers/net/cxgb3/cxgb3_ioctl.h [new file with mode: 0644]
drivers/net/cxgb3/cxgb3_main.c [new file with mode: 0644]
drivers/net/cxgb3/cxgb3_offload.c [new file with mode: 0644]
drivers/net/cxgb3/cxgb3_offload.h [new file with mode: 0644]
drivers/net/cxgb3/firmware_exports.h [new file with mode: 0644]
drivers/net/cxgb3/l2t.c [new file with mode: 0644]
drivers/net/cxgb3/l2t.h [new file with mode: 0644]
drivers/net/cxgb3/mc5.c [new file with mode: 0644]
drivers/net/cxgb3/regs.h [new file with mode: 0644]
drivers/net/cxgb3/sge.c [new file with mode: 0644]
drivers/net/cxgb3/sge_defs.h [new file with mode: 0644]
drivers/net/cxgb3/t3_cpl.h [new file with mode: 0644]
drivers/net/cxgb3/t3_hw.c [new file with mode: 0644]
drivers/net/cxgb3/t3cdev.h [new file with mode: 0644]
drivers/net/cxgb3/version.h [new file with mode: 0644]
drivers/net/cxgb3/vsc8211.c [new file with mode: 0644]
drivers/net/cxgb3/xgmac.c [new file with mode: 0644]
drivers/net/declance.c
drivers/net/e1000/e1000.h
drivers/net/e1000/e1000_ethtool.c
drivers/net/e1000/e1000_main.c
drivers/net/e1000/e1000_osdep.h
drivers/net/e1000/e1000_param.c
drivers/net/forcedeth.c
drivers/net/hp100.c
drivers/net/iseries_veth.c
drivers/net/ixgb/ixgb.h
drivers/net/ixgb/ixgb_ethtool.c
drivers/net/ixgb/ixgb_main.c
drivers/net/macb.c
drivers/net/macb.h
drivers/net/mace.c
drivers/net/macmace.c
drivers/net/macsonic.c
drivers/net/myri10ge/myri10ge.c
drivers/net/netxen/netxen_nic.h
drivers/net/netxen/netxen_nic_ethtool.c
drivers/net/netxen/netxen_nic_init.c
drivers/net/oaknet.c [deleted file]
drivers/net/pasemi_mac.c [new file with mode: 0644]
drivers/net/pasemi_mac.h [new file with mode: 0644]
drivers/net/qla3xxx.c [changed mode: 0644->0755]
drivers/net/qla3xxx.h [changed mode: 0644->0755]
drivers/net/s2io-regs.h
drivers/net/s2io.c
drivers/net/s2io.h
drivers/net/sc92031.c [new file with mode: 0644]
drivers/net/sk_mca.c [deleted file]
drivers/net/sk_mca.h [deleted file]
drivers/net/skfp/can.c [deleted file]
drivers/net/skfp/drvfbi.c
drivers/net/skfp/fplustm.c
drivers/net/skfp/smt.c
drivers/net/skge.c
drivers/net/skge.h
drivers/net/sky2.c
drivers/net/sky2.h
drivers/net/smc911x.c
drivers/net/smc91x.c
drivers/net/spider_net.c
drivers/net/spider_net.h
drivers/net/spider_net_ethtool.c
drivers/net/tg3.c
drivers/net/ucc_geth.c
drivers/net/wan/Kconfig
drivers/net/wan/Makefile
drivers/net/wan/hdlc.c
drivers/net/wan/pc300too.c [new file with mode: 0644]
drivers/net/wan/z85230.c
drivers/net/wireless/bcm43xx/bcm43xx.h
drivers/net/wireless/bcm43xx/bcm43xx_leds.c
drivers/net/wireless/bcm43xx/bcm43xx_main.c
drivers/net/wireless/bcm43xx/bcm43xx_radio.c
drivers/net/wireless/bcm43xx/bcm43xx_radio.h
drivers/net/wireless/hostap/hostap_main.c
drivers/net/wireless/ipw2200.c
drivers/net/wireless/orinoco.c
drivers/net/wireless/orinoco_cs.c
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/prism54/islpci_dev.h
drivers/net/wireless/prism54/islpci_hotplug.c
drivers/net/wireless/spectrum_cs.c
drivers/net/wireless/zd1211rw/zd_chip.c
drivers/net/wireless/zd1211rw/zd_chip.h
drivers/net/wireless/zd1211rw/zd_def.h
drivers/net/wireless/zd1211rw/zd_ieee80211.h
drivers/net/wireless/zd1211rw/zd_rf.h
drivers/net/wireless/zd1211rw/zd_types.h [deleted file]
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/net/wireless/zd1211rw/zd_usb.h
drivers/pci/hotplug/Kconfig
drivers/pci/hotplug/acpiphp_glue.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_ctrl.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/hotplug/sgi_hotplug.c
drivers/pci/hotplug/shpchp.h
drivers/pci/hotplug/shpchp_core.c
drivers/pci/hotplug/shpchp_ctrl.c
drivers/pci/hotplug/shpchp_hpc.c
drivers/pci/msi.c
drivers/pci/pci-driver.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/probe.c
drivers/pci/quirks.c
drivers/pci/search.c
drivers/pcmcia/cs.c
drivers/pcmcia/cs_internal.h
drivers/pcmcia/ds.c
drivers/pcmcia/i82092.c
drivers/pcmcia/i82365.c
drivers/pcmcia/pcmcia_ioctl.c
drivers/pcmcia/pcmcia_resource.c
drivers/pcmcia/pd6729.c
drivers/pcmcia/rsrc_nonstatic.c
drivers/pcmcia/soc_common.c
drivers/pcmcia/socket_sysfs.c
drivers/pcmcia/tcic.c
drivers/pcmcia/yenta_socket.c
drivers/pnp/pnpacpi/Kconfig
drivers/pnp/system.c
drivers/s390/Kconfig
drivers/s390/Makefile
drivers/s390/block/dasd.c
drivers/s390/block/dasd_3990_erp.c
drivers/s390/block/dasd_devmap.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_eer.c
drivers/s390/block/dasd_erp.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dasd_genhd.c
drivers/s390/block/dasd_int.h
drivers/s390/block/dasd_proc.c
drivers/s390/block/dcssblk.c
drivers/s390/char/Makefile
drivers/s390/char/con3215.c
drivers/s390/char/con3270.c
drivers/s390/char/defkeymap.c
drivers/s390/char/fs3270.c
drivers/s390/char/keyboard.c
drivers/s390/char/monwriter.c
drivers/s390/char/raw3270.c
drivers/s390/char/sclp.c
drivers/s390/char/sclp.h
drivers/s390/char/sclp_con.c
drivers/s390/char/sclp_cpi.c
drivers/s390/char/sclp_info.c [new file with mode: 0644]
drivers/s390/char/sclp_rw.c
drivers/s390/char/sclp_tty.c
drivers/s390/char/sclp_vt220.c
drivers/s390/char/tape.h
drivers/s390/char/tape_3590.c
drivers/s390/char/tape_3590.h
drivers/s390/char/tape_block.c
drivers/s390/char/tape_char.c
drivers/s390/char/tape_core.c
drivers/s390/char/tty3270.c
drivers/s390/char/vmlogrdr.c
drivers/s390/cio/blacklist.c
drivers/s390/cio/ccwgroup.c
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc.h
drivers/s390/cio/cio.c
drivers/s390/cio/cmf.c
drivers/s390/cio/css.c
drivers/s390/cio/css.h
drivers/s390/cio/device.c
drivers/s390/cio/device.h
drivers/s390/cio/device_fsm.c
drivers/s390/cio/device_ops.c
drivers/s390/cio/device_status.c
drivers/s390/cio/qdio.c
drivers/s390/crypto/ap_bus.c
drivers/s390/crypto/zcrypt_api.c
drivers/s390/crypto/zcrypt_pcica.c
drivers/s390/crypto/zcrypt_pcixcc.c
drivers/s390/net/claw.c
drivers/s390/net/ctcmain.c
drivers/s390/net/cu3088.c
drivers/s390/net/lcs.c
drivers/s390/net/netiucv.c
drivers/s390/net/qeth_eddp.c
drivers/s390/net/qeth_main.c
drivers/s390/net/qeth_sys.c
drivers/s390/s390mach.c
drivers/s390/s390mach.h
drivers/s390/scsi/zfcp_aux.c
drivers/s390/scsi/zfcp_dbf.c
drivers/s390/scsi/zfcp_erp.c
drivers/s390/scsi/zfcp_ext.h
drivers/s390/scsi/zfcp_fsf.c
drivers/s390/scsi/zfcp_qdio.c
drivers/s390/scsi/zfcp_scsi.c
drivers/s390/sysinfo.c
drivers/scsi/ipr.c
drivers/spi/pxa2xx_spi.c
drivers/spi/spi.c
drivers/spi/spi_bitbang.c
drivers/spi/spi_butterfly.c
drivers/usb/atm/speedtch.c
drivers/usb/class/usblp.c
drivers/usb/core/Kconfig
drivers/usb/core/buffer.c
drivers/usb/core/devices.c
drivers/usb/core/devio.c
drivers/usb/core/driver.c
drivers/usb/core/file.c
drivers/usb/core/generic.c
drivers/usb/core/hcd.c
drivers/usb/core/hcd.h
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/sysfs.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/at91_udc.h
drivers/usb/gadget/config.c
drivers/usb/gadget/epautoconf.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/gadget_chips.h
drivers/usb/gadget/gmidi.c
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/lh7a40x_udc.h
drivers/usb/gadget/net2280.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/pxa2xx_udc.c
drivers/usb/gadget/serial.c
drivers/usb/gadget/usbstring.c
drivers/usb/gadget/zero.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-dbg.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-hub.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-ps3.c [new file with mode: 0644]
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci.h
drivers/usb/host/ohci-at91.c
drivers/usb/host/ohci-au1xxx.c
drivers/usb/host/ohci-ep93xx.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-lh7a404.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/ohci-pnx4008.c
drivers/usb/host/ohci-pnx8550.c
drivers/usb/host/ohci-ppc-of.c [new file with mode: 0644]
drivers/usb/host/ohci-ppc-soc.c
drivers/usb/host/ohci-ps3.c [new file with mode: 0644]
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/ohci-s3c2410.c
drivers/usb/host/ohci-sa1111.c
drivers/usb/host/ohci.h
drivers/usb/host/uhci-debug.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/uhci-hcd.h
drivers/usb/host/uhci-q.c
drivers/usb/image/mdc800.c
drivers/usb/input/Kconfig
drivers/usb/input/Makefile
drivers/usb/input/gtco.c [new file with mode: 0644]
drivers/usb/input/hid-core.c
drivers/usb/input/hid-ff.c
drivers/usb/input/hid-lgff.c
drivers/usb/input/hid-plff.c [new file with mode: 0644]
drivers/usb/misc/idmouse.c
drivers/usb/misc/rio500.c
drivers/usb/mon/Makefile
drivers/usb/mon/mon_bin.c [new file with mode: 0644]
drivers/usb/mon/mon_dma.c
drivers/usb/mon/mon_main.c
drivers/usb/mon/mon_text.c
drivers/usb/mon/usb_mon.h
drivers/usb/net/Kconfig
drivers/usb/net/asix.c
drivers/usb/net/cdc_ether.c
drivers/usb/net/kaweth.c
drivers/usb/net/pegasus.h
drivers/usb/net/rndis_host.c
drivers/usb/serial/aircable.c
drivers/usb/serial/airprime.c
drivers/usb/serial/ark3116.c
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/bus.c
drivers/usb/serial/cp2101.c
drivers/usb/serial/cyberjack.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/empeg.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/funsoft.c
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/generic.c
drivers/usb/serial/hp4x.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_edgeport.h
drivers/usb/serial/io_tables.h
drivers/usb/serial/io_ti.c
drivers/usb/serial/io_usbvend.h
drivers/usb/serial/ipaq.c
drivers/usb/serial/ipw.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan.h
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/navman.c
drivers/usb/serial/omninet.c
drivers/usb/serial/option.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/safe_serial.c
drivers/usb/serial/sierra.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/visor.c
drivers/usb/serial/visor.h
drivers/usb/serial/whiteheat.c
drivers/usb/storage/onetouch.c
drivers/usb/storage/scsiglue.c
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/usb.c
drivers/video/output.c [new file with mode: 0644]
fs/cifs/CHANGES
fs/cifs/cifsfs.c
fs/cifs/file.c
fs/cifs/readdir.c
fs/cifs/smbdes.c
fs/dlm/Kconfig
fs/dlm/config.c
fs/dlm/config.h
fs/dlm/dlm_internal.h
fs/dlm/lock.c
fs/dlm/lockspace.c
fs/dlm/lowcomms-sctp.c
fs/dlm/lowcomms-tcp.c
fs/dlm/midcomms.c
fs/dlm/rcom.c
fs/dlm/recover.c
fs/dlm/recoverd.c
fs/dlm/user.c
fs/dlm/util.c
fs/gfs2/Kconfig
fs/gfs2/bmap.c
fs/gfs2/dir.c
fs/gfs2/dir.h
fs/gfs2/eattr.c
fs/gfs2/glock.c
fs/gfs2/glock.h
fs/gfs2/glops.c
fs/gfs2/incore.h
fs/gfs2/inode.c
fs/gfs2/lm.c
fs/gfs2/locking/dlm/lock_dlm.h
fs/gfs2/locking/dlm/main.c
fs/gfs2/locking/dlm/mount.c
fs/gfs2/locking/dlm/sysfs.c
fs/gfs2/lops.c
fs/gfs2/ops_address.c
fs/gfs2/ops_dentry.c
fs/gfs2/ops_export.c
fs/gfs2/ops_file.c
fs/gfs2/ops_inode.c
fs/gfs2/ops_super.c
fs/gfs2/ops_vm.c
fs/gfs2/super.c
fs/gfs2/sys.c
fs/jfs/inode.c
fs/jfs/jfs_debug.h
fs/jfs/jfs_dmap.c
fs/jfs/jfs_imap.c
fs/jfs/jfs_incore.h
fs/jfs/jfs_lock.h
fs/jfs/jfs_metapage.c
fs/jfs/jfs_txnmgr.c
fs/jfs/jfs_xtree.c
fs/jfs/namei.c
fs/ocfs2/journal.h
fs/sysfs/bin.c
fs/sysfs/dir.c
fs/sysfs/file.c
fs/sysfs/group.c
fs/sysfs/inode.c
fs/sysfs/mount.c
fs/sysfs/symlink.c
fs/sysfs/sysfs.h
include/acpi/acconfig.h
include/acpi/acdebug.h
include/acpi/acdisasm.h
include/acpi/acdispat.h
include/acpi/acevents.h
include/acpi/acexcep.h
include/acpi/acglobal.h
include/acpi/achware.h
include/acpi/acinterp.h
include/acpi/aclocal.h
include/acpi/acmacros.h
include/acpi/acnames.h
include/acpi/acnamesp.h
include/acpi/acobject.h
include/acpi/acopcode.h
include/acpi/acoutput.h
include/acpi/acparser.h
include/acpi/acpi.h
include/acpi/acpi_bus.h
include/acpi/acpi_drivers.h
include/acpi/acpiosxf.h
include/acpi/acpixf.h
include/acpi/acresrc.h
include/acpi/acstruct.h
include/acpi/actables.h
include/acpi/actbl.h
include/acpi/actbl1.h
include/acpi/actbl2.h [deleted file]
include/acpi/actbl71.h [deleted file]
include/acpi/actypes.h
include/acpi/acutils.h
include/acpi/amlcode.h
include/acpi/amlresrc.h
include/acpi/platform/acenv.h
include/acpi/platform/acgcc.h
include/acpi/platform/aclinux.h
include/asm-alpha/pci.h
include/asm-i386/acpi.h
include/asm-i386/mach-es7000/mach_mpparse.h
include/asm-ia64/acpi.h
include/asm-ia64/dma.h
include/asm-ia64/esi.h
include/asm-ia64/machvec.h
include/asm-ia64/meminit.h
include/asm-ia64/pgalloc.h
include/asm-ia64/sn/acpi.h
include/asm-ia64/sn/pcibr_provider.h
include/asm-ia64/sn/pcidev.h
include/asm-ia64/swiotlb.h [new file with mode: 0644]
include/asm-ia64/thread_info.h
include/asm-ia64/unistd.h
include/asm-mips/bootinfo.h
include/asm-mips/ddb5xxx/ddb5477.h
include/asm-mips/dec/interrupts.h
include/asm-mips/dma.h
include/asm-mips/emma2rh/emma2rh.h
include/asm-mips/emma2rh/markeins.h
include/asm-mips/i8259.h
include/asm-mips/io.h
include/asm-mips/irq.h
include/asm-mips/irq_cpu.h
include/asm-mips/mach-au1x00/au1000.h
include/asm-mips/mach-cobalt/cobalt.h
include/asm-mips/mach-emma2rh/irq.h
include/asm-mips/mach-generic/irq.h
include/asm-mips/mach-mips/irq.h
include/asm-mips/mach-vr41xx/irq.h [new file with mode: 0644]
include/asm-mips/mips-boards/atlasint.h
include/asm-mips/mips-boards/maltaint.h
include/asm-mips/mips-boards/prom.h
include/asm-mips/mips-boards/seadint.h
include/asm-mips/mips-boards/simint.h
include/asm-mips/mipsmtregs.h
include/asm-mips/page.h
include/asm-mips/rtlx.h
include/asm-mips/sections.h
include/asm-mips/sgi/ip22.h
include/asm-mips/smtc_ipi.h
include/asm-mips/uaccess.h
include/asm-mips/vr41xx/cmbvr4133.h
include/asm-s390/compat.h
include/asm-s390/etr.h [new file with mode: 0644]
include/asm-s390/hardirq.h
include/asm-s390/io.h
include/asm-s390/kdebug.h
include/asm-s390/lowcore.h
include/asm-s390/mmu_context.h
include/asm-s390/pgalloc.h
include/asm-s390/pgtable.h
include/asm-s390/processor.h
include/asm-s390/ptrace.h
include/asm-s390/reset.h
include/asm-s390/sclp.h [new file with mode: 0644]
include/asm-s390/sections.h
include/asm-s390/setup.h
include/asm-s390/sfp-util.h [new file with mode: 0644]
include/asm-s390/smp.h
include/asm-s390/system.h
include/asm-s390/tape390.h
include/asm-s390/timer.h
include/asm-s390/timex.h
include/asm-s390/tlbflush.h
include/asm-s390/uaccess.h
include/asm-x86_64/acpi.h
include/asm-x86_64/swiotlb.h
include/linux/Kbuild
include/linux/acpi.h
include/linux/device.h
include/linux/hid-debug.h
include/linux/hid.h
include/linux/ide.h
include/linux/irq.h
include/linux/kobject.h
include/linux/mmc/card.h
include/linux/mmc/host.h
include/linux/mmc/mmc.h
include/linux/mmc/protocol.h
include/linux/module.h
include/linux/msi.h
include/linux/netdevice.h
include/linux/pci.h
include/linux/pci_ids.h
include/linux/serio.h
include/linux/spi/spi.h
include/linux/sysfs.h
include/linux/tifm.h
include/linux/usb.h
include/linux/usb/Kbuild [new file with mode: 0644]
include/linux/usb/ch9.h [new file with mode: 0644]
include/linux/usb/serial.h
include/linux/usb_ch9.h [deleted file]
include/linux/usb_gadgetfs.h
include/linux/video_output.h [new file with mode: 0644]
include/pcmcia/ss.h
include/rdma/ib_user_mad.h
include/rdma/ib_verbs.h
kernel/irq/chip.c
kernel/module.c
kernel/params.c
lib/kobject.c
lib/swiotlb.c
net/bridge/br_if.c
net/bridge/br_sysfs_br.c
net/bridge/br_sysfs_if.c
net/core/dev.c
net/core/net-sysfs.c
net/core/skbuff.c
net/ieee80211/softmac/ieee80211softmac_wx.c
scripts/Kbuild.include
scripts/gen_initramfs_list.sh
scripts/makelst
security/keys/key.c

index 8d51c14..48123db 100644 (file)
@@ -30,6 +30,7 @@ are not a good substitute for a solid C education and/or years of
 experience, the following books are good for, if anything, reference:
  - "The C Programming Language" by Kernighan and Ritchie [Prentice Hall]
  - "Practical C Programming" by Steve Oualline [O'Reilly]
+ - "C:  A Reference Manual" by Harbison and Steele [Prentice Hall]
 
 The kernel is written using GNU C and the GNU toolchain.  While it
 adheres to the ISO C89 standard, it uses a number of extensions that are
index 0ba6af0..2dc5e5d 100644 (file)
@@ -274,6 +274,7 @@ Who:        Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
 
 ---------------------------
 
+<<<<<<< test:Documentation/feature-removal-schedule.txt
 What:  ACPI hotkey driver (CONFIG_ACPI_HOTKEY)
 When:  2.6.21
 Why:   hotkey.c was an attempt to consolidate multiple drivers that use
@@ -306,11 +307,18 @@ Why:      The ACPI namespace is effectively the symbol list for
        the BIOS can be extracted and disassembled with acpidump
        and iasl as documented in the pmtools package here:
        http://ftp.kernel.org/pub/linux/kernel/people/lenb/acpi/utils
-
 Who:   Len Brown <len.brown@intel.com>
 
 ---------------------------
 
+What:  ACPI procfs interface
+When:  July 2007
+Why:   After ACPI sysfs conversion, ACPI attributes will be duplicated
+       in sysfs and the ACPI procfs interface should be removed.
+Who:   Zhang Rui <rui.zhang@intel.com>
+
+---------------------------
+
 What:  /proc/acpi/button
 When:  August 2007
 Why:   /proc/acpi/button has been replaced by events to the input layer
@@ -325,3 +333,10 @@ Why:       Unmaintained for years, superceded by JFFS2 for years.
 Who:   Jeff Garzik <jeff@garzik.org>
 
 ---------------------------
+
+What:   sk98lin network driver
+When:   July 2007
+Why:    In kernel tree version of driver is unmaintained. Sk98lin driver
+       replaced by the skge driver. 
+Who:    Stephen Hemminger <shemminger@osdl.org>
+
index 3f9ddbc..0993969 100644 (file)
@@ -480,7 +480,7 @@ r2       argument 0 / return value 0                call-clobbered
 r3       argument 1 / return value 1 (if long long) call-clobbered
 r4       argument 2                                 call-clobbered
 r5       argument 3                                 call-clobbered
-r6      argument 5                                 saved
+r6      argument 4                                 saved
 r7       pointer-to arguments 5 to ...              saved      
 r8       this & that                                saved
 r9       this & that                                saved
index 22c5331..077e903 100644 (file)
@@ -213,15 +213,16 @@ C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
 
 Interface descriptor info (can be multiple per Config):
 
-I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
-|   |      |      |       |             |      |       |__Driver name
-|   |      |      |       |             |      |          or "(none)"
-|   |      |      |       |             |      |__InterfaceProtocol
-|   |      |      |       |             |__InterfaceSubClass
-|   |      |      |       |__InterfaceClass
-|   |      |      |__NumberOfEndpoints
-|   |      |__AlternateSettingNumber
-|   |__InterfaceNumber
+I:* If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
+| | |      |      |       |             |      |       |__Driver name
+| | |      |      |       |             |      |          or "(none)"
+| | |      |      |       |             |      |__InterfaceProtocol
+| | |      |      |       |             |__InterfaceSubClass
+| | |      |      |       |__InterfaceClass
+| | |      |      |__NumberOfEndpoints
+| | |      |__AlternateSettingNumber
+| | |__InterfaceNumber
+| |__ "*" indicates the active altsetting (others are " ")
 |__Interface info tag
 
     A given interface may have one or more "alternate" settings.
@@ -277,7 +278,7 @@ of the USB devices on a system's root hub.  (See more below
 on how to do this.)
 
 The Interface lines can be used to determine what driver is
-being used for each device.
+being used for each device, and which altsetting it activated.
 
 The Configuration lines could be used to list maximum power
 (in milliamps) that a system's USB devices are using.
index e65ec82..0f6808a 100644 (file)
@@ -77,7 +77,7 @@ that the file size is not excessive for your favourite editor.
 
 The '1t' type data consists of a stream of events, such as URB submission,
 URB callback, submission error. Every event is a text line, which consists
-of whitespace separated words. The number of position of words may depend
+of whitespace separated words. The number or position of words may depend
 on the event type, but there is a set of words, common for all types.
 
 Here is the list of words, from left to right:
@@ -170,4 +170,152 @@ dd65f0e8 4128379808 C Bo:005:02 0 31 >
 
 * Raw binary format and API
 
-TBD
+The overall architecture of the API is about the same as the one above,
+only the events are delivered in binary format. Each event is sent in
+the following structure (its name is made up, so that we can refer to it):
+
+struct usbmon_packet {
+       u64 id;                 /*  0: URB ID - from submission to callback */
+       unsigned char type;     /*  8: Same as text; extensible. */
+       unsigned char xfer_type; /*    ISO (0), Intr, Control, Bulk (3) */
+       unsigned char epnum;    /*     Endpoint number and transfer direction */
+       unsigned char devnum;   /*     Device address */
+       u16 busnum;             /* 12: Bus number */
+       char flag_setup;        /* 14: Same as text */
+       char flag_data;         /* 15: Same as text; Binary zero is OK. */
+       s64 ts_sec;             /* 16: gettimeofday */
+       s32 ts_usec;            /* 24: gettimeofday */
+       int status;             /* 28: */
+       unsigned int length;    /* 32: Length of data (submitted or actual) */
+       unsigned int len_cap;   /* 36: Delivered length */
+       unsigned char setup[8]; /* 40: Only for Control 'S' */
+};                             /* 48 bytes total */
+
+These events can be received from a character device by reading with read(2),
+with an ioctl(2), or by accessing the buffer with mmap.
+
+The character device is usually called /dev/usbmonN, where N is the USB bus
+number. Number zero (/dev/usbmon0) is special and means "all buses".
+However, this feature is not implemented yet. Note that specific naming
+policy is set by your Linux distribution.
+
+If you create /dev/usbmon0 by hand, make sure that it is owned by root
+and has mode 0600. Otherwise, unpriviledged users will be able to snoop
+keyboard traffic.
+
+The following ioctl calls are available, with MON_IOC_MAGIC 0x92:
+
+ MON_IOCQ_URB_LEN, defined as _IO(MON_IOC_MAGIC, 1)
+
+This call returns the length of data in the next event. Note that majority of
+events contain no data, so if this call returns zero, it does not mean that
+no events are available.
+
+ MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+
+The argument is a pointer to the following structure:
+
+struct mon_bin_stats {
+       u32 queued;
+       u32 dropped;
+};
+
+The member "queued" refers to the number of events currently queued in the
+buffer (and not to the number of events processed since the last reset).
+
+The member "dropped" is the number of events lost since the last call
+to MON_IOCG_STATS.
+
+ MON_IOCT_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 4)
+
+This call sets the buffer size. The argument is the size in bytes.
+The size may be rounded down to the next chunk (or page). If the requested
+size is out of [unspecified] bounds for this kernel, the call fails with
+-EINVAL.
+
+ MON_IOCQ_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 5)
+
+This call returns the current size of the buffer in bytes.
+
+ MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg)
+
+This call waits for events to arrive if none were in the kernel buffer,
+then returns the first event. Its argument is a pointer to the following
+structure:
+
+struct mon_get_arg {
+       struct usbmon_packet *hdr;
+       void *data;
+       size_t alloc;           /* Length of data (can be zero) */
+};
+
+Before the call, hdr, data, and alloc should be filled. Upon return, the area
+pointed by hdr contains the next event structure, and the data buffer contains
+the data, if any. The event is removed from the kernel buffer.
+
+ MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg)
+
+This ioctl is primarily used when the application accesses the buffer
+with mmap(2). Its argument is a pointer to the following structure:
+
+struct mon_mfetch_arg {
+       uint32_t *offvec;       /* Vector of events fetched */
+       uint32_t nfetch;        /* Number of events to fetch (out: fetched) */
+       uint32_t nflush;        /* Number of events to flush */
+};
+
+The ioctl operates in 3 stages.
+
+First, it removes and discards up to nflush events from the kernel buffer.
+The actual number of events discarded is returned in nflush.
+
+Second, it waits for an event to be present in the buffer, unless the pseudo-
+device is open with O_NONBLOCK.
+
+Third, it extracts up to nfetch offsets into the mmap buffer, and stores
+them into the offvec. The actual number of event offsets is stored into
+the nfetch.
+
+ MON_IOCH_MFLUSH, defined as _IO(MON_IOC_MAGIC, 8)
+
+This call removes a number of events from the kernel buffer. Its argument
+is the number of events to remove. If the buffer contains fewer events
+than requested, all events present are removed, and no error is reported.
+This works when no events are available too.
+
+ FIONBIO
+
+The ioctl FIONBIO may be implemented in the future, if there's a need.
+
+In addition to ioctl(2) and read(2), the special file of binary API can
+be polled with select(2) and poll(2). But lseek(2) does not work.
+
+* Memory-mapped access of the kernel buffer for the binary API
+
+The basic idea is simple:
+
+To prepare, map the buffer by getting the current size, then using mmap(2).
+Then, execute a loop similar to the one written in pseudo-code below:
+
+   struct mon_mfetch_arg fetch;
+   struct usbmon_packet *hdr;
+   int nflush = 0;
+   for (;;) {
+      fetch.offvec = vec; // Has N 32-bit words
+      fetch.nfetch = N;   // Or less than N
+      fetch.nflush = nflush;
+      ioctl(fd, MON_IOCX_MFETCH, &fetch);   // Process errors, too
+      nflush = fetch.nfetch;       // This many packets to flush when done
+      for (i = 0; i < nflush; i++) {
+         hdr = (struct ubsmon_packet *) &mmap_area[vec[i]];
+         if (hdr->type == '@')     // Filler packet
+            continue;
+         caddr_t data = &mmap_area[vec[i]] + 64;
+         process_packet(hdr, data);
+      }
+   }
+
+Thus, the main idea is to execute only one ioctl per N events.
+
+Although the buffer is circular, the returned headers and data do not cross
+the end of the buffer, so the above pseudo-code does not need any gathering.
diff --git a/Documentation/video-output.txt b/Documentation/video-output.txt
new file mode 100644 (file)
index 0000000..e517011
--- /dev/null
@@ -0,0 +1,34 @@
+
+               Video Output Switcher Control
+               ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+               2006 luming.yu@intel.com
+
+The output sysfs class driver provides an abstract video output layer that
+can be used to hook platform specific methods to enable/disable video output
+device through common sysfs interface. For example, on my IBM ThinkPad T42
+laptop, The ACPI video driver registered its output devices and read/write
+method for 'state' with output sysfs class. The user interface under sysfs is:
+
+linux:/sys/class/video_output # tree .
+.
+|-- CRT0
+|   |-- device -> ../../../devices/pci0000:00/0000:00:01.0
+|   |-- state
+|   |-- subsystem -> ../../../class/video_output
+|   `-- uevent
+|-- DVI0
+|   |-- device -> ../../../devices/pci0000:00/0000:00:01.0
+|   |-- state
+|   |-- subsystem -> ../../../class/video_output
+|   `-- uevent
+|-- LCD0
+|   |-- device -> ../../../devices/pci0000:00/0000:00:01.0
+|   |-- state
+|   |-- subsystem -> ../../../class/video_output
+|   `-- uevent
+`-- TV0
+   |-- device -> ../../../devices/pci0000:00/0000:00:01.0
+   |-- state
+   |-- subsystem -> ../../../class/video_output
+   `-- uevent
+
index 0ad8803..fe35f3a 100644 (file)
@@ -584,12 +584,30 @@ W:        http://sourceforge.net/projects/acpi4asus
 W:     http://xf.iksaif.net/acpi4asus
 S:     Maintained
 
+ASUS LAPTOP EXTRAS DRIVER
+P:     Corentin Chary
+M:     corentincj@iksaif.net
+L:     acpi4asus-user@lists.sourceforge.net
+W:     http://sourceforge.net/projects/acpi4asus
+W:     http://xf.iksaif.net/acpi4asus
+S:     Maintained
+
 ATA OVER ETHERNET DRIVER
 P:     Ed L. Cashin
 M:     ecashin@coraid.com
 W:     http://www.coraid.com/support/linux
 S:     Supported
 
+ATL1 ETHERNET DRIVER
+P:     Jay Cliburn
+M:     jcliburn@gmail.com
+P:     Chris Snook
+M:     csnook@redhat.com
+L:     atl1-devel@lists.sourceforge.net
+W:     http://sourceforge.net/projects/atl1
+W:     http://atl1.sourceforge.net
+S:     Maintained
+
 ATM
 P:     Chas Williams
 M:     chas@cmf.nrl.navy.mil
@@ -2477,6 +2495,12 @@ L:       orinoco-devel@lists.sourceforge.net
 W:     http://www.nongnu.org/orinoco/
 S:     Maintained
 
+PA SEMI ETHERNET DRIVER
+P:     Olof Johansson
+M:     olof@lixom.net
+L:     netdev@vger.kernel.org
+S:     Maintained
+
 PARALLEL PORT SUPPORT
 P:     Phil Blundell
 M:     philb@gnu.org
@@ -2646,7 +2670,7 @@ S:        Supported
 
 PRISM54 WIRELESS DRIVER
 P:     Prism54 Development Team
-M:     prism54-private@prism54.org
+M:     developers@islsm.org
 L:     netdev@vger.kernel.org
 W:     http://prism54.org
 S:     Maintained
@@ -2791,7 +2815,7 @@ M:        schwidefsky@de.ibm.com
 P:     Heiko Carstens
 M:     heiko.carstens@de.ibm.com
 M:     linux390@de.ibm.com
-L:     linux-390@vm.marist.edu
+L:     linux-s390@vger.kernel.org
 W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
 
@@ -2799,7 +2823,7 @@ S390 NETWORK DRIVERS
 P:     Frank Pavlic
 M:     fpavlic@de.ibm.com
 M:     linux390@de.ibm.com
-L:     linux-390@vm.marist.edu
+L:     linux-s390@vger.kernel.org
 W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
 
@@ -2807,7 +2831,7 @@ S390 ZFCP DRIVER
 P:     Swen Schillig
 M:     swen@vnet.ibm.com
 M:     linux390@de.ibm.com
-L:     linux-390@vm.marist.edu
+L:     linux-s390@vger.kernel.org
 W:     http://www.ibm.com/developerworks/linux/linux390/
 S:     Supported
 
@@ -3647,7 +3671,7 @@ S:        Maintained
 W83L51xD SD/MMC CARD INTERFACE DRIVER
 P:     Pierre Ossman
 M:     drzeus-wbsd@drzeus.cx
-L:     wbsd-devel@list.drzeus.cx
+L:     linux-kernel@vger.kernel.org
 W:     http://projects.drzeus.cx/wbsd
 S:     Maintained
 
index 7e2750f..cdeda68 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -776,7 +776,7 @@ $(vmlinux-dirs): prepare scripts
 #        $(EXTRAVERSION)               eg, -rc6
 #      $(localver-full)
 #        $(localver)
-#          localversion*               (all localversion* files)
+#          localversion*               (files without backups, containing '~')
 #          $(CONFIG_LOCALVERSION)      (from kernel config setting)
 #        $(localver-auto)              (only if CONFIG_LOCALVERSION_AUTO is set)
 #          ./scripts/setlocalversion   (SCM tag, if one exists)
@@ -787,17 +787,12 @@ $(vmlinux-dirs): prepare scripts
 # moment, only git is supported but other SCMs can edit the script
 # scripts/setlocalversion and add the appropriate checks as needed.
 
-nullstring :=
-space      := $(nullstring) # end of line
+pattern = ".*/localversion[^~]*"
+string  = $(shell cat /dev/null \
+          `find $(objtree) $(srctree) -maxdepth 1 -regex $(pattern) | sort`)
 
-___localver = $(objtree)/localversion* $(srctree)/localversion*
-__localver  = $(sort $(wildcard $(___localver)))
-# skip backup files (containing '~')
-_localver = $(foreach f, $(__localver), $(if $(findstring ~, $(f)),,$(f)))
-
-localver = $(subst $(space),, \
-          $(shell cat /dev/null $(_localver)) \
-          $(patsubst "%",%,$(CONFIG_LOCALVERSION)))
+localver = $(subst $(space),, $(string) \
+                             $(patsubst "%",%,$(CONFIG_LOCALVERSION)))
 
 # If CONFIG_LOCALVERSION_AUTO is set scripts/setlocalversion is called
 # and if the SCM is know a tag from the SCM is appended.
index 3c10b9a..ab642a4 100644 (file)
@@ -575,3 +575,7 @@ void pci_iounmap(struct pci_dev *dev, void __iomem * addr)
 
 EXPORT_SYMBOL(pci_iomap);
 EXPORT_SYMBOL(pci_iounmap);
+
+/* FIXME: Some boxes have multiple ISA bridges! */
+struct pci_dev *isa_bridge;
+EXPORT_SYMBOL(isa_bridge);
index 5d80edf..bb0c376 100644 (file)
@@ -466,7 +466,8 @@ CONFIG_FW_LOADER=y
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
+CONFIG_PNP=y
+CONFIG_PNPACPI=y
 
 #
 # Block devices
index cbcb2c2..e94aff6 100644 (file)
@@ -66,7 +66,7 @@ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) { return
 
 #define BAD_MADT_ENTRY(entry, end) (                                       \
                (!entry) || (unsigned long)entry + sizeof(*entry) > end ||  \
-               ((acpi_table_entry_header *)entry)->length < sizeof(*entry))
+               ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
 
 #define PREFIX                 "ACPI: "
 
@@ -79,7 +79,7 @@ int acpi_ioapic;
 int acpi_strict;
 EXPORT_SYMBOL(acpi_strict);
 
-acpi_interrupt_flags acpi_sci_flags __initdata;
+u8 acpi_sci_flags __initdata;
 int acpi_sci_override_gsi __initdata;
 int acpi_skip_timer_override __initdata;
 int acpi_use_timer_override __initdata;
@@ -92,11 +92,6 @@ static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
 #warning ACPI uses CMPXCHG, i486 and later hardware
 #endif
 
-#define MAX_MADT_ENTRIES       256
-u8 x86_acpiid_to_apicid[MAX_MADT_ENTRIES] =
-    {[0 ... MAX_MADT_ENTRIES - 1] = 0xff };
-EXPORT_SYMBOL(x86_acpiid_to_apicid);
-
 /* --------------------------------------------------------------------------
                               Boot-time Configuration
    -------------------------------------------------------------------------- */
@@ -166,30 +161,26 @@ char *__acpi_map_table(unsigned long phys, unsigned long size)
 
 #ifdef CONFIG_PCI_MMCONFIG
 /* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
-struct acpi_table_mcfg_config *pci_mmcfg_config;
+struct acpi_mcfg_allocation *pci_mmcfg_config;
 int pci_mmcfg_config_num;
 
-int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
+int __init acpi_parse_mcfg(struct acpi_table_header *header)
 {
        struct acpi_table_mcfg *mcfg;
        unsigned long i;
        int config_size;
 
-       if (!phys_addr || !size)
+       if (!header)
                return -EINVAL;
 
-       mcfg = (struct acpi_table_mcfg *)__acpi_map_table(phys_addr, size);
-       if (!mcfg) {
-               printk(KERN_WARNING PREFIX "Unable to map MCFG\n");
-               return -ENODEV;
-       }
+       mcfg = (struct acpi_table_mcfg *)header;
 
        /* how many config structures do we have */
        pci_mmcfg_config_num = 0;
-       i = size - sizeof(struct acpi_table_mcfg);
-       while (i >= sizeof(struct acpi_table_mcfg_config)) {
+       i = header->length - sizeof(struct acpi_table_mcfg);
+       while (i >= sizeof(struct acpi_mcfg_allocation)) {
                ++pci_mmcfg_config_num;
-               i -= sizeof(struct acpi_table_mcfg_config);
+               i -= sizeof(struct acpi_mcfg_allocation);
        };
        if (pci_mmcfg_config_num == 0) {
                printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
@@ -204,9 +195,9 @@ int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
                return -ENOMEM;
        }
 
-       memcpy(pci_mmcfg_config, &mcfg->config, config_size);
+       memcpy(pci_mmcfg_config, &mcfg[1], config_size);
        for (i = 0; i < pci_mmcfg_config_num; ++i) {
-               if (mcfg->config[i].base_reserved) {
+               if (pci_mmcfg_config[i].address > 0xFFFFFFFF) {
                        printk(KERN_ERR PREFIX
                               "MMCONFIG not in low 4GB of memory\n");
                        kfree(pci_mmcfg_config);
@@ -220,24 +211,24 @@ int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
 #endif                         /* CONFIG_PCI_MMCONFIG */
 
 #ifdef CONFIG_X86_LOCAL_APIC
-static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_madt(struct acpi_table_header *table)
 {
        struct acpi_table_madt *madt = NULL;
 
-       if (!phys_addr || !size || !cpu_has_apic)
+       if (!cpu_has_apic)
                return -EINVAL;
 
-       madt = (struct acpi_table_madt *)__acpi_map_table(phys_addr, size);
+       madt = (struct acpi_table_madt *)table;
        if (!madt) {
                printk(KERN_WARNING PREFIX "Unable to map MADT\n");
                return -ENODEV;
        }
 
-       if (madt->lapic_address) {
-               acpi_lapic_addr = (u64) madt->lapic_address;
+       if (madt->address) {
+               acpi_lapic_addr = (u64) madt->address;
 
                printk(KERN_DEBUG PREFIX "Local APIC address 0x%08x\n",
-                      madt->lapic_address);
+                      madt->address);
        }
 
        acpi_madt_oem_check(madt->header.oem_id, madt->header.oem_table_id);
@@ -246,21 +237,17 @@ static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
 }
 
 static int __init
-acpi_parse_lapic(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_lapic(struct acpi_subtable_header * header, const unsigned long end)
 {
-       struct acpi_table_lapic *processor = NULL;
+       struct acpi_madt_local_apic *processor = NULL;
 
-       processor = (struct acpi_table_lapic *)header;
+       processor = (struct acpi_madt_local_apic *)header;
 
        if (BAD_MADT_ENTRY(processor, end))
                return -EINVAL;
 
        acpi_table_print_madt_entry(header);
 
-       /* Record local apic id only when enabled */
-       if (processor->flags.enabled)
-               x86_acpiid_to_apicid[processor->acpi_id] = processor->id;
-
        /*
         * We need to register disabled CPU as well to permit
         * counting disabled CPUs. This allows us to size
@@ -269,18 +256,18 @@ acpi_parse_lapic(acpi_table_entry_header * header, const unsigned long end)
         * when we use CPU hotplug.
         */
        mp_register_lapic(processor->id,        /* APIC ID */
-                         processor->flags.enabled);    /* Enabled? */
+                         processor->lapic_flags & ACPI_MADT_ENABLED);  /* Enabled? */
 
        return 0;
 }
 
 static int __init
-acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header,
+acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header,
                          const unsigned long end)
 {
-       struct acpi_table_lapic_addr_ovr *lapic_addr_ovr = NULL;
+       struct acpi_madt_local_apic_override *lapic_addr_ovr = NULL;
 
-       lapic_addr_ovr = (struct acpi_table_lapic_addr_ovr *)header;
+       lapic_addr_ovr = (struct acpi_madt_local_apic_override *)header;
 
        if (BAD_MADT_ENTRY(lapic_addr_ovr, end))
                return -EINVAL;
@@ -291,11 +278,11 @@ acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header,
 }
 
 static int __init
-acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end)
 {
-       struct acpi_table_lapic_nmi *lapic_nmi = NULL;
+       struct acpi_madt_local_apic_nmi *lapic_nmi = NULL;
 
-       lapic_nmi = (struct acpi_table_lapic_nmi *)header;
+       lapic_nmi = (struct acpi_madt_local_apic_nmi *)header;
 
        if (BAD_MADT_ENTRY(lapic_nmi, end))
                return -EINVAL;
@@ -313,11 +300,11 @@ acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end)
 #ifdef CONFIG_X86_IO_APIC
 
 static int __init
-acpi_parse_ioapic(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end)
 {
-       struct acpi_table_ioapic *ioapic = NULL;
+       struct acpi_madt_io_apic *ioapic = NULL;
 
-       ioapic = (struct acpi_table_ioapic *)header;
+       ioapic = (struct acpi_madt_io_apic *)header;
 
        if (BAD_MADT_ENTRY(ioapic, end))
                return -EINVAL;
@@ -342,11 +329,11 @@ static void __init acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
                polarity = 3;
 
        /* Command-line over-ride via acpi_sci= */
-       if (acpi_sci_flags.trigger)
-               trigger = acpi_sci_flags.trigger;
+       if (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)
+               trigger = (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2;
 
-       if (acpi_sci_flags.polarity)
-               polarity = acpi_sci_flags.polarity;
+       if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK)
+               polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK;
 
        /*
         * mp_config_acpi_legacy_irqs() already setup IRQs < 16
@@ -357,51 +344,52 @@ static void __init acpi_sci_ioapic_setup(u32 gsi, u16 polarity, u16 trigger)
 
        /*
         * stash over-ride to indicate we've been here
-        * and for later update of acpi_fadt
+        * and for later update of acpi_gbl_FADT
         */
        acpi_sci_override_gsi = gsi;
        return;
 }
 
 static int __init
-acpi_parse_int_src_ovr(acpi_table_entry_header * header,
+acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
                       const unsigned long end)
 {
-       struct acpi_table_int_src_ovr *intsrc = NULL;
+       struct acpi_madt_interrupt_override *intsrc = NULL;
 
-       intsrc = (struct acpi_table_int_src_ovr *)header;
+       intsrc = (struct acpi_madt_interrupt_override *)header;
 
        if (BAD_MADT_ENTRY(intsrc, end))
                return -EINVAL;
 
        acpi_table_print_madt_entry(header);
 
-       if (intsrc->bus_irq == acpi_fadt.sci_int) {
+       if (intsrc->source_irq == acpi_gbl_FADT.sci_interrupt) {
                acpi_sci_ioapic_setup(intsrc->global_irq,
-                                     intsrc->flags.polarity,
-                                     intsrc->flags.trigger);
+                                     intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
+                                     (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
                return 0;
        }
 
        if (acpi_skip_timer_override &&
-           intsrc->bus_irq == 0 && intsrc->global_irq == 2) {
+           intsrc->source_irq == 0 && intsrc->global_irq == 2) {
                printk(PREFIX "BIOS IRQ0 pin2 override ignored.\n");
                return 0;
        }
 
-       mp_override_legacy_irq(intsrc->bus_irq,
-                              intsrc->flags.polarity,
-                              intsrc->flags.trigger, intsrc->global_irq);
+       mp_override_legacy_irq(intsrc->source_irq,
+                               intsrc->inti_flags & ACPI_MADT_POLARITY_MASK,
+                               (intsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2,
+                               intsrc->global_irq);
 
        return 0;
 }
 
 static int __init
-acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end)
 {
-       struct acpi_table_nmi_src *nmi_src = NULL;
+       struct acpi_madt_nmi_source *nmi_src = NULL;
 
-       nmi_src = (struct acpi_table_nmi_src *)header;
+       nmi_src = (struct acpi_madt_nmi_source *)header;
 
        if (BAD_MADT_ENTRY(nmi_src, end))
                return -EINVAL;
@@ -417,7 +405,7 @@ acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end)
 
 /*
  * acpi_pic_sci_set_trigger()
- * 
+ *
  * use ELCR to set PIC-mode trigger type for SCI
  *
  * If a PIC-mode SCI is not recognized or gives spurious IRQ7's
@@ -511,7 +499,7 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
 {
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *obj;
-       struct acpi_table_lapic *lapic;
+       struct acpi_madt_local_apic *lapic;
        cpumask_t tmp_map, new_map;
        u8 physid;
        int cpu;
@@ -529,10 +517,10 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
                return -EINVAL;
        }
 
-       lapic = (struct acpi_table_lapic *)obj->buffer.pointer;
+       lapic = (struct acpi_madt_local_apic *)obj->buffer.pointer;
 
-       if ((lapic->header.type != ACPI_MADT_LAPIC) ||
-           (!lapic->flags.enabled)) {
+       if (lapic->header.type != ACPI_MADT_TYPE_LOCAL_APIC ||
+           !(lapic->lapic_flags & ACPI_MADT_ENABLED)) {
                kfree(buffer.pointer);
                return -EINVAL;
        }
@@ -544,7 +532,7 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
        buffer.pointer = NULL;
 
        tmp_map = cpu_present_map;
-       mp_register_lapic(physid, lapic->flags.enabled);
+       mp_register_lapic(physid, lapic->lapic_flags & ACPI_MADT_ENABLED);
 
        /*
         * If mp_register_lapic successfully generates a new logical cpu
@@ -566,14 +554,6 @@ EXPORT_SYMBOL(acpi_map_lsapic);
 
 int acpi_unmap_lsapic(int cpu)
 {
-       int i;
-
-       for_each_possible_cpu(i) {
-               if (x86_acpiid_to_apicid[i] == x86_cpu_to_apicid[cpu]) {
-                       x86_acpiid_to_apicid[i] = -1;
-                       break;
-               }
-       }
        x86_cpu_to_apicid[cpu] = -1;
        cpu_clear(cpu, cpu_present_map);
        num_processors--;
@@ -619,42 +599,36 @@ acpi_scan_rsdp(unsigned long start, unsigned long length)
        return 0;
 }
 
-static int __init acpi_parse_sbf(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_sbf(struct acpi_table_header *table)
 {
-       struct acpi_table_sbf *sb;
-
-       if (!phys_addr || !size)
-               return -EINVAL;
+       struct acpi_table_boot *sb;
 
-       sb = (struct acpi_table_sbf *)__acpi_map_table(phys_addr, size);
+       sb = (struct acpi_table_boot *)table;
        if (!sb) {
                printk(KERN_WARNING PREFIX "Unable to map SBF\n");
                return -ENODEV;
        }
 
-       sbf_port = sb->sbf_cmos;        /* Save CMOS port */
+       sbf_port = sb->cmos_index;      /* Save CMOS port */
 
        return 0;
 }
 
 #ifdef CONFIG_HPET_TIMER
 
-static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
+static int __init acpi_parse_hpet(struct acpi_table_header *table)
 {
        struct acpi_table_hpet *hpet_tbl;
        struct resource *hpet_res;
        resource_size_t res_start;
 
-       if (!phys || !size)
-               return -EINVAL;
-
-       hpet_tbl = (struct acpi_table_hpet *)__acpi_map_table(phys, size);
+       hpet_tbl = (struct acpi_table_hpet *)table;
        if (!hpet_tbl) {
                printk(KERN_WARNING PREFIX "Unable to map HPET\n");
                return -ENODEV;
        }
 
-       if (hpet_tbl->addr.space_id != ACPI_SPACE_MEM) {
+       if (hpet_tbl->address.space_id != ACPI_SPACE_MEM) {
                printk(KERN_WARNING PREFIX "HPET timers must be located in "
                       "memory.\n");
                return -1;
@@ -667,29 +641,28 @@ static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
                hpet_res->name = (void *)&hpet_res[1];
                hpet_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
                snprintf((char *)hpet_res->name, HPET_RESOURCE_NAME_SIZE,
-                        "HPET %u", hpet_tbl->number);
+                        "HPET %u", hpet_tbl->sequence);
                hpet_res->end = (1 * 1024) - 1;
        }
 
-#ifdef CONFIG_X86_64
-       vxtime.hpet_address = hpet_tbl->addr.addrl |
-           ((long)hpet_tbl->addr.addrh << 32);
+#ifdef CONFIG_X86_64
+       vxtime.hpet_address = hpet_tbl->address.address;
 
        printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
-              hpet_tbl->id, vxtime.hpet_address);
+               hpet_tbl->id, vxtime.hpet_address);
 
        res_start = vxtime.hpet_address;
-#else                          /* X86 */
+#else                          /* X86 */
        {
                extern unsigned long hpet_address;
 
-               hpet_address = hpet_tbl->addr.addrl;
+               hpet_address = hpet_tbl->address.address;
                printk(KERN_INFO PREFIX "HPET id: %#x base: %#lx\n",
-                      hpet_tbl->id, hpet_address);
+                       hpet_tbl->id, hpet_address);
 
                res_start = hpet_address;
        }
-#endif                         /* X86 */
+#endif                         /* X86 */
 
        if (hpet_res) {
                hpet_res->start = res_start;
@@ -707,42 +680,28 @@ static int __init acpi_parse_hpet(unsigned long phys, unsigned long size)
 extern u32 pmtmr_ioport;
 #endif
 
-static int __init acpi_parse_fadt(unsigned long phys, unsigned long size)
+static int __init acpi_parse_fadt(struct acpi_table_header *table)
 {
-       struct fadt_descriptor *fadt = NULL;
-
-       fadt = (struct fadt_descriptor *)__acpi_map_table(phys, size);
-       if (!fadt) {
-               printk(KERN_WARNING PREFIX "Unable to map FADT\n");
-               return 0;
-       }
-       /* initialize sci_int early for INT_SRC_OVR MADT parsing */
-       acpi_fadt.sci_int = fadt->sci_int;
-
-       /* initialize rev and apic_phys_dest_mode for x86_64 genapic */
-       acpi_fadt.revision = fadt->revision;
-       acpi_fadt.force_apic_physical_destination_mode =
-           fadt->force_apic_physical_destination_mode;
 
 #ifdef CONFIG_X86_PM_TIMER
        /* detect the location of the ACPI PM Timer */
-       if (fadt->revision >= FADT2_REVISION_ID) {
+       if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID) {
                /* FADT rev. 2 */
-               if (fadt->xpm_tmr_blk.address_space_id !=
+               if (acpi_gbl_FADT.xpm_timer_block.space_id !=
                    ACPI_ADR_SPACE_SYSTEM_IO)
                        return 0;
 
-               pmtmr_ioport = fadt->xpm_tmr_blk.address;
+               pmtmr_ioport = acpi_gbl_FADT.xpm_timer_block.address;
                /*
                 * "X" fields are optional extensions to the original V1.0
                 * fields, so we must selectively expand V1.0 fields if the
                 * corresponding X field is zero.
                 */
                if (!pmtmr_ioport)
-                       pmtmr_ioport = fadt->V1_pm_tmr_blk;
+                       pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
        } else {
                /* FADT rev. 1 */
-               pmtmr_ioport = fadt->V1_pm_tmr_blk;
+               pmtmr_ioport = acpi_gbl_FADT.pm_timer_block;
        }
        if (pmtmr_ioport)
                printk(KERN_INFO PREFIX "PM-Timer IO Port: %#x\n",
@@ -784,13 +743,13 @@ static int __init acpi_parse_madt_lapic_entries(void)
        if (!cpu_has_apic)
                return -ENODEV;
 
-       /* 
+       /*
         * Note that the LAPIC address is obtained from the MADT (32-bit value)
         * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value).
         */
 
        count =
-           acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR,
+           acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE,
                                  acpi_parse_lapic_addr_ovr, 0);
        if (count < 0) {
                printk(KERN_ERR PREFIX
@@ -800,7 +759,7 @@ static int __init acpi_parse_madt_lapic_entries(void)
 
        mp_register_lapic_address(acpi_lapic_addr);
 
-       count = acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic,
+       count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC, acpi_parse_lapic,
                                      MAX_APICS);
        if (!count) {
                printk(KERN_ERR PREFIX "No LAPIC entries present\n");
@@ -813,7 +772,7 @@ static int __init acpi_parse_madt_lapic_entries(void)
        }
 
        count =
-           acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0);
+           acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0);
        if (count < 0) {
                printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
                /* TBD: Cleanup to allow fallback to MPS */
@@ -842,7 +801,7 @@ static int __init acpi_parse_madt_ioapic_entries(void)
                return -ENODEV;
        }
 
-       if (!cpu_has_apic) 
+       if (!cpu_has_apic)
                return -ENODEV;
 
        /*
@@ -855,7 +814,7 @@ static int __init acpi_parse_madt_ioapic_entries(void)
        }
 
        count =
-           acpi_table_parse_madt(ACPI_MADT_IOAPIC, acpi_parse_ioapic,
+           acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic,
                                  MAX_IO_APICS);
        if (!count) {
                printk(KERN_ERR PREFIX "No IOAPIC entries present\n");
@@ -866,7 +825,7 @@ static int __init acpi_parse_madt_ioapic_entries(void)
        }
 
        count =
-           acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr,
+           acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr,
                                  NR_IRQ_VECTORS);
        if (count < 0) {
                printk(KERN_ERR PREFIX
@@ -880,13 +839,13 @@ static int __init acpi_parse_madt_ioapic_entries(void)
         * pretend we got one so we can set the SCI flags.
         */
        if (!acpi_sci_override_gsi)
-               acpi_sci_ioapic_setup(acpi_fadt.sci_int, 0, 0);
+               acpi_sci_ioapic_setup(acpi_gbl_FADT.sci_interrupt, 0, 0);
 
        /* Fill in identity legacy mapings where no override */
        mp_config_acpi_legacy_irqs();
 
        count =
-           acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src,
+           acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src,
                                  NR_IRQ_VECTORS);
        if (count < 0) {
                printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
@@ -908,7 +867,7 @@ static void __init acpi_process_madt(void)
 #ifdef CONFIG_X86_LOCAL_APIC
        int count, error;
 
-       count = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
+       count = acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt);
        if (count >= 1) {
 
                /*
@@ -1195,7 +1154,7 @@ int __init acpi_boot_table_init(void)
        if (acpi_disabled && !acpi_ht)
                return 1;
 
-       /* 
+       /*
         * Initialize the ACPI boot-time table parser.
         */
        error = acpi_table_init();
@@ -1204,7 +1163,7 @@ int __init acpi_boot_table_init(void)
                return error;
        }
 
-       acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
+       acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
 
        /*
         * blacklist may disable ACPI entirely
@@ -1232,19 +1191,19 @@ int __init acpi_boot_init(void)
        if (acpi_disabled && !acpi_ht)
                return 1;
 
-       acpi_table_parse(ACPI_BOOT, acpi_parse_sbf);
+       acpi_table_parse(ACPI_SIG_BOOT, acpi_parse_sbf);
 
        /*
         * set sci_int and PM timer address
         */
-       acpi_table_parse(ACPI_FADT, acpi_parse_fadt);
+       acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt);
 
        /*
         * Process the Multiple APIC Description Table (MADT), if present
         */
        acpi_process_madt();
 
-       acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
+       acpi_table_parse(ACPI_SIG_HPET, acpi_parse_hpet);
 
        return 0;
 }
@@ -1315,13 +1274,17 @@ static int __init setup_acpi_sci(char *s)
        if (!s)
                return -EINVAL;
        if (!strcmp(s, "edge"))
-               acpi_sci_flags.trigger = 1;
+               acpi_sci_flags =  ACPI_MADT_TRIGGER_EDGE |
+                       (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
        else if (!strcmp(s, "level"))
-               acpi_sci_flags.trigger = 3;
+               acpi_sci_flags = ACPI_MADT_TRIGGER_LEVEL |
+                       (acpi_sci_flags & ~ACPI_MADT_TRIGGER_MASK);
        else if (!strcmp(s, "high"))
-               acpi_sci_flags.polarity = 1;
+               acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_HIGH |
+                       (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
        else if (!strcmp(s, "low"))
-               acpi_sci_flags.polarity = 3;
+               acpi_sci_flags = ACPI_MADT_POLARITY_ACTIVE_LOW |
+                       (acpi_sci_flags & ~ACPI_MADT_POLARITY_MASK);
        else
                return -EINVAL;
        return 0;
index 4b60af7..bf86f76 100644 (file)
@@ -16,7 +16,7 @@
 
 static int nvidia_hpet_detected __initdata;
 
-static int __init nvidia_hpet_check(unsigned long phys, unsigned long size)
+static int __init nvidia_hpet_check(struct acpi_table_header *header)
 {
        nvidia_hpet_detected = 1;
        return 0;
@@ -30,7 +30,7 @@ static int __init check_bridge(int vendor, int device)
           is enabled. */
        if (!acpi_use_timer_override && vendor == PCI_VENDOR_ID_NVIDIA) {
                nvidia_hpet_detected = 0;
-               acpi_table_parse(ACPI_HPET, nvidia_hpet_check);
+               acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check);
                if (nvidia_hpet_detected == 0) {
                        acpi_skip_timer_override = 1;
                          printk(KERN_INFO "Nvidia board "
index e940e00..a3db933 100644 (file)
@@ -190,7 +190,7 @@ static void do_powersaver(int cx_address, unsigned int clock_ratio_index)
                /* Invoke C3 */
                inb(cx_address);
                /* Dummy op - must do something useless after P_LVL3 read */
-               t = inl(acpi_fadt.xpm_tmr_blk.address);
+               t = inl(acpi_gbl_FADT.xpm_timer_block.address);
        }
        /* Disable bus ratio bit */
        local_irq_disable();
@@ -250,8 +250,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
                outb(3, 0x22);
        } else if ((pr != NULL) && pr->flags.bm_control) {
                /* Disable bus master arbitration */
-               acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
-                                 ACPI_MTX_DO_NOT_LOCK);
+               acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
        }
        switch (longhaul_version) {
 
@@ -281,8 +280,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
        case TYPE_POWERSAVER:
                if (longhaul_flags & USE_ACPI_C3) {
                        /* Don't allow wakeup */
-                       acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0,
-                                         ACPI_MTX_DO_NOT_LOCK);
+                       acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
                        do_powersaver(cx->address, clock_ratio_index);
                } else {
                        do_powersaver(0, clock_ratio_index);
@@ -295,8 +293,7 @@ static void longhaul_setstate(unsigned int clock_ratio_index)
                outb(0, 0x22);
        } else if ((pr != NULL) && pr->flags.bm_control) {
                /* Enable bus master arbitration */
-               acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
-                                 ACPI_MTX_DO_NOT_LOCK);
+               acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
        }
        outb(pic2_mask,0xA1);   /* restore mask */
        outb(pic1_mask,0x21);
@@ -414,7 +411,7 @@ static int __init longhaul_get_ranges(void)
        highest_speed = calc_speed(maxmult);
        lowest_speed = calc_speed(minmult);
        dprintk ("FSB:%dMHz  Lowest speed: %s   Highest speed:%s\n", fsb,
-                print_speed(lowest_speed/1000), 
+                print_speed(lowest_speed/1000),
                 print_speed(highest_speed/1000));
 
        if (lowest_speed == highest_speed) {
@@ -498,7 +495,7 @@ static void __init longhaul_setup_voltagescaling(void)
                maxvid.mV/1000, maxvid.mV%1000,
                minvid.mV/1000, minvid.mV%1000,
                numvscales);
-       
+
        j = 0;
        while (longhaul_table[j].frequency != CPUFREQ_TABLE_END) {
                speed = longhaul_table[j].frequency;
index 6a3875f..5592fa6 100644 (file)
@@ -2606,25 +2606,32 @@ static struct irq_chip msi_chip = {
        .retrigger      = ioapic_retrigger_irq,
 };
 
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
 {
        struct msi_msg msg;
-       int ret;
+       int irq, ret;
+       irq = create_irq();
+       if (irq < 0)
+               return irq;
+
+       set_irq_msi(irq, desc);
        ret = msi_compose_msg(dev, irq, &msg);
-       if (ret < 0)
+       if (ret < 0) {
+               destroy_irq(irq);
                return ret;
+       }
 
        write_msi_msg(irq, &msg);
 
        set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq,
                                      "edge");
 
-       return 0;
+       return irq;
 }
 
 void arch_teardown_msi_irq(unsigned int irq)
 {
-       return;
+       destroy_irq(irq);
 }
 
 #endif /* CONFIG_PCI_MSI */
index 49bff35..4f5983c 100644 (file)
@@ -1057,7 +1057,7 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity)
        static int              gsi_to_irq[MAX_GSI_NUM];
 
        /* Don't set up the ACPI SCI because it's already set up */
-       if (acpi_fadt.sci_int == gsi)
+       if (acpi_gbl_FADT.sci_interrupt == gsi)
                return gsi;
 
        ioapic = mp_find_ioapic(gsi);
@@ -1114,7 +1114,7 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity)
                        /*
                         * Don't assign IRQ used by ACPI SCI
                         */
-                       if (gsi == acpi_fadt.sci_int)
+                       if (gsi == acpi_gbl_FADT.sci_interrupt)
                                gsi = pci_irq++;
                        gsi_to_irq[irq] = gsi;
                } else {
index f7e735c..2a8713e 100644 (file)
@@ -62,19 +62,19 @@ extern void * boot_ioremap(unsigned long, unsigned long);
 /* Identify CPU proximity domains */
 static void __init parse_cpu_affinity_structure(char *p)
 {
-       struct acpi_table_processor_affinity *cpu_affinity = 
-                               (struct acpi_table_processor_affinity *) p;
+       struct acpi_srat_cpu_affinity *cpu_affinity =
+                               (struct acpi_srat_cpu_affinity *) p;
 
-       if (!cpu_affinity->flags.enabled)
+       if ((cpu_affinity->flags & ACPI_SRAT_CPU_ENABLED) == 0)
                return;         /* empty entry */
 
        /* mark this node as "seen" in node bitmap */
-       BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain);
+       BMAP_SET(pxm_bitmap, cpu_affinity->proximity_domain_lo);
 
-       apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain;
+       apicid_to_pxm[cpu_affinity->apic_id] = cpu_affinity->proximity_domain_lo;
 
        printk("CPU 0x%02X in proximity domain 0x%02X\n",
-               cpu_affinity->apic_id, cpu_affinity->proximity_domain);
+               cpu_affinity->apic_id, cpu_affinity->proximity_domain_lo);
 }
 
 /*
@@ -84,28 +84,27 @@ static void __init parse_cpu_affinity_structure(char *p)
 static void __init parse_memory_affinity_structure (char *sratp)
 {
        unsigned long long paddr, size;
-       unsigned long start_pfn, end_pfn; 
+       unsigned long start_pfn, end_pfn;
        u8 pxm;
        struct node_memory_chunk_s *p, *q, *pend;
-       struct acpi_table_memory_affinity *memory_affinity =
-                       (struct acpi_table_memory_affinity *) sratp;
+       struct acpi_srat_mem_affinity *memory_affinity =
+                       (struct acpi_srat_mem_affinity *) sratp;
 
-       if (!memory_affinity->flags.enabled)
+       if ((memory_affinity->flags & ACPI_SRAT_MEM_ENABLED) == 0)
                return;         /* empty entry */
 
+       pxm = memory_affinity->proximity_domain & 0xff;
+
        /* mark this node as "seen" in node bitmap */
-       BMAP_SET(pxm_bitmap, memory_affinity->proximity_domain);
+       BMAP_SET(pxm_bitmap, pxm);
 
        /* calculate info for memory chunk structure */
-       paddr = memory_affinity->base_addr_hi;
-       paddr = (paddr << 32) | memory_affinity->base_addr_lo;
-       size = memory_affinity->length_hi;
-       size = (size << 32) | memory_affinity->length_lo;
-       
+       paddr = memory_affinity->base_address;
+       size = memory_affinity->length;
+
        start_pfn = paddr >> PAGE_SHIFT;
        end_pfn = (paddr + size) >> PAGE_SHIFT;
-       
-       pxm = memory_affinity->proximity_domain;
+
 
        if (num_memory_chunks >= MAXCHUNKS) {
                printk("Too many mem chunks in SRAT. Ignoring %lld MBytes at %llx\n",
@@ -132,8 +131,8 @@ static void __init parse_memory_affinity_structure (char *sratp)
        printk("Memory range 0x%lX to 0x%lX (type 0x%X) in proximity domain 0x%02X %s\n",
                start_pfn, end_pfn,
                memory_affinity->memory_type,
-               memory_affinity->proximity_domain,
-               (memory_affinity->flags.hot_pluggable ?
+               pxm,
+               ((memory_affinity->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) ?
                 "enabled and removable" : "enabled" ) );
 }
 
@@ -185,10 +184,10 @@ static int __init acpi20_parse_srat(struct acpi_table_srat *sratp)
        num_memory_chunks = 0;
        while (p < end) {
                switch (*p) {
-               case ACPI_SRAT_PROCESSOR_AFFINITY:
+               case ACPI_SRAT_TYPE_CPU_AFFINITY:
                        parse_cpu_affinity_structure(p);
                        break;
-               case ACPI_SRAT_MEMORY_AFFINITY:
+               case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
                        parse_memory_affinity_structure(p);
                        break;
                default:
@@ -262,31 +261,30 @@ out_fail:
        return 0;
 }
 
+struct acpi_static_rsdt {
+       struct acpi_table_rsdt table;
+       u32 padding[7]; /* Allow for 7 more table entries */
+};
+
 int __init get_memcfg_from_srat(void)
 {
        struct acpi_table_header *header = NULL;
        struct acpi_table_rsdp *rsdp = NULL;
        struct acpi_table_rsdt *rsdt = NULL;
-       struct acpi_pointer *rsdp_address = NULL;
-       struct acpi_table_rsdt saved_rsdt;
+       acpi_native_uint rsdp_address = 0;
+       struct acpi_static_rsdt saved_rsdt;
        int tables = 0;
        int i = 0;
 
-       if (ACPI_FAILURE(acpi_find_root_pointer(ACPI_PHYSICAL_ADDRESSING,
-                                               rsdp_address))) {
+       rsdp_address = acpi_find_rsdp();
+       if (!rsdp_address) {
                printk("%s: System description tables not found\n",
                       __FUNCTION__);
                goto out_err;
        }
 
-       if (rsdp_address->pointer_type == ACPI_PHYSICAL_POINTER) {
-               printk("%s: assigning address to rsdp\n", __FUNCTION__);
-               rsdp = (struct acpi_table_rsdp *)
-                               (u32)rsdp_address->pointer.physical;
-       } else {
-               printk("%s: rsdp_address is not a physical pointer\n", __FUNCTION__);
-               goto out_err;
-       }
+       printk("%s: assigning address to rsdp\n", __FUNCTION__);
+       rsdp = (struct acpi_table_rsdp *)(u32)rsdp_address;
        if (!rsdp) {
                printk("%s: Didn't find ACPI root!\n", __FUNCTION__);
                goto out_err;
@@ -295,13 +293,13 @@ int __init get_memcfg_from_srat(void)
        printk(KERN_INFO "%.8s v%d [%.6s]\n", rsdp->signature, rsdp->revision,
                rsdp->oem_id);
 
-       if (strncmp(rsdp->signature, RSDP_SIG,strlen(RSDP_SIG))) {
+       if (strncmp(rsdp->signature, ACPI_SIG_RSDP,strlen(ACPI_SIG_RSDP))) {
                printk(KERN_WARNING "%s: RSDP table signature incorrect\n", __FUNCTION__);
                goto out_err;
        }
 
        rsdt = (struct acpi_table_rsdt *)
-           boot_ioremap(rsdp->rsdt_address, sizeof(struct acpi_table_rsdt));
+           boot_ioremap(rsdp->rsdt_physical_address, sizeof(struct acpi_table_rsdt));
 
        if (!rsdt) {
                printk(KERN_WARNING
@@ -310,9 +308,9 @@ int __init get_memcfg_from_srat(void)
                goto out_err;
        }
 
-       header = & rsdt->header;
+       header = &rsdt->header;
 
-       if (strncmp(header->signature, RSDT_SIG, strlen(RSDT_SIG))) {
+       if (strncmp(header->signature, ACPI_SIG_RSDT, strlen(ACPI_SIG_RSDT))) {
                printk(KERN_WARNING "ACPI: RSDT signature incorrect\n");
                goto out_err;
        }
@@ -330,9 +328,9 @@ int __init get_memcfg_from_srat(void)
 
        memcpy(&saved_rsdt, rsdt, sizeof(saved_rsdt));
 
-       if (saved_rsdt.header.length > sizeof(saved_rsdt)) {
+       if (saved_rsdt.table.header.length > sizeof(saved_rsdt)) {
                printk(KERN_WARNING "ACPI: Too big length in RSDT: %d\n",
-                      saved_rsdt.header.length);
+                      saved_rsdt.table.header.length);
                goto out_err;
        }
 
@@ -341,15 +339,15 @@ int __init get_memcfg_from_srat(void)
        for (i = 0; i < tables; i++) {
                /* Map in header, then map in full table length. */
                header = (struct acpi_table_header *)
-                       boot_ioremap(saved_rsdt.entry[i], sizeof(struct acpi_table_header));
+                       boot_ioremap(saved_rsdt.table.table_offset_entry[i], sizeof(struct acpi_table_header));
                if (!header)
                        break;
                header = (struct acpi_table_header *)
-                       boot_ioremap(saved_rsdt.entry[i], header->length);
+                       boot_ioremap(saved_rsdt.table.table_offset_entry[i], header->length);
                if (!header)
                        break;
 
-               if (strncmp((char *) &header->signature, "SRAT", 4))
+               if (strncmp((char *) &header->signature, ACPI_SIG_SRAT, 4))
                        continue;
 
                /* we've found the srat table. don't need to look at any more tables */
index 80566ca..c8d5aa1 100644 (file)
@@ -84,15 +84,6 @@ struct es7000_oem_table {
 };
 
 #ifdef CONFIG_ACPI
-struct acpi_table_sdt {
-       unsigned long pa;
-       unsigned long count;
-       struct {
-               unsigned long pa;
-               enum acpi_table_id id;
-               unsigned long size;
-       }       entry[50];
-};
 
 struct oem_table {
        struct acpi_table_header Header;
index 3d0fc85..9be6cea 100644 (file)
@@ -160,51 +160,14 @@ parse_unisys_oem (char *oemptr)
 int __init
 find_unisys_acpi_oem_table(unsigned long *oem_addr)
 {
-       struct acpi_table_rsdp          *rsdp = NULL;
-       unsigned long                   rsdp_phys = 0;
-       struct acpi_table_header        *header = NULL;
-       int                             i;
-       struct acpi_table_sdt           sdt;
-
-       rsdp_phys = acpi_find_rsdp();
-       rsdp = __va(rsdp_phys);
-       if (rsdp->rsdt_address) {
-               struct acpi_table_rsdt  *mapped_rsdt = NULL;
-               sdt.pa = rsdp->rsdt_address;
-
-               header = (struct acpi_table_header *)
-                       __acpi_map_table(sdt.pa, sizeof(struct acpi_table_header));
-               if (!header)
-                       return -ENODEV;
-
-               sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 3;
-               mapped_rsdt = (struct acpi_table_rsdt *)
-                       __acpi_map_table(sdt.pa, header->length);
-               if (!mapped_rsdt)
-                       return -ENODEV;
-
-               header = &mapped_rsdt->header;
-
-               for (i = 0; i < sdt.count; i++)
-                       sdt.entry[i].pa = (unsigned long) mapped_rsdt->entry[i];
-       };
-       for (i = 0; i < sdt.count; i++) {
-
-               header = (struct acpi_table_header *)
-                       __acpi_map_table(sdt.entry[i].pa,
-                               sizeof(struct acpi_table_header));
-               if (!header)
-                       continue;
-               if (!strncmp((char *) &header->signature, "OEM1", 4)) {
-                       if (!strncmp((char *) &header->oem_id, "UNISYS", 6)) {
-                               void *addr;
-                               struct oem_table *t;
-                               acpi_table_print(header, sdt.entry[i].pa);
-                               t = (struct oem_table *) __acpi_map_table(sdt.entry[i].pa, header->length);
-                               addr = (void *) __acpi_map_table(t->OEMTableAddr, t->OEMTableSize);
-                               *oem_addr = (unsigned long) addr;
-                               return 0;
-                       }
+       struct acpi_table_header *header = NULL;
+       int i = 0;
+       while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) {
+               if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) {
+                       struct oem_table *t = (struct oem_table *)header;
+                       *oem_addr = (unsigned long)__acpi_map_table(t->OEMTableAddr,
+                                                                   t->OEMTableSize);
+                       return 0;
                }
        }
        return -1;
index e2616a2..5700220 100644 (file)
@@ -36,7 +36,7 @@ static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32);
 static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
 {
        int cfg_num = -1;
-       struct acpi_table_mcfg_config *cfg;
+       struct acpi_mcfg_allocation *cfg;
 
        if (seg == 0 && bus < MAX_CHECK_BUS &&
            test_bit(PCI_SLOT(devfn) + 32*bus, fallback_slots))
@@ -48,11 +48,11 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
                        break;
                }
                cfg = &pci_mmcfg_config[cfg_num];
-               if (cfg->pci_segment_group_number != seg)
+               if (cfg->pci_segment != seg)
                        continue;
                if ((cfg->start_bus_number <= bus) &&
                    (cfg->end_bus_number >= bus))
-                       return cfg->base_address;
+                       return cfg->address;
        }
 
        /* Handle more broken MCFG tables on Asus etc.
@@ -60,9 +60,9 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
           this applies to all busses. */
        cfg = &pci_mmcfg_config[0];
        if (pci_mmcfg_config_num == 1 &&
-               cfg->pci_segment_group_number == 0 &&
+               cfg->pci_segment == 0 &&
                (cfg->start_bus_number | cfg->end_bus_number) == 0)
-               return cfg->base_address;
+               return cfg->address;
 
        /* Fall back to type 0 */
        return 0;
@@ -125,7 +125,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
        unsigned long flags;
        u32 base;
 
-       if ((bus > 255) || (devfn > 255) || (reg > 4095)) 
+       if ((bus > 255) || (devfn > 255) || (reg > 4095))
                return -EINVAL;
 
        base = get_base_addr(seg, bus, devfn);
@@ -199,19 +199,19 @@ void __init pci_mmcfg_init(int type)
        if ((pci_probe & PCI_PROBE_MMCONF) == 0)
                return;
 
-       acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+       acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
        if ((pci_mmcfg_config_num == 0) ||
            (pci_mmcfg_config == NULL) ||
-           (pci_mmcfg_config[0].base_address == 0))
+           (pci_mmcfg_config[0].address == 0))
                return;
 
        /* Only do this check when type 1 works. If it doesn't work
           assume we run on a Mac and always use MCFG */
-       if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].base_address,
-                       pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
+       if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].address,
+                       pci_mmcfg_config[0].address + MMCONFIG_APER_MIN,
                        E820_RESERVED)) {
-               printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
-                               pci_mmcfg_config[0].base_address);
+               printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not E820-reserved\n",
+                               (unsigned long)pci_mmcfg_config[0].address);
                printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
                return;
        }
index fcacfe2..f1d2899 100644 (file)
@@ -11,6 +11,8 @@ menu "Processor type and features"
 
 config IA64
        bool
+       select PCI if (!IA64_HP_SIM)
+       select ACPI if (!IA64_HP_SIM)
        default y
        help
          The Itanium Processor Family is Intel's 64-bit successor to
@@ -28,7 +30,6 @@ config MMU
 
 config SWIOTLB
        bool
-       default y
 
 config RWSEM_XCHGADD_ALGORITHM
        bool
@@ -84,10 +85,9 @@ choice
 
 config IA64_GENERIC
        bool "generic"
-       select ACPI
-       select PCI
        select NUMA
        select ACPI_NUMA
+       select SWIOTLB
        help
          This selects the system type of your hardware.  A "generic" kernel
          will run on any supported IA-64 system.  However, if you configure
@@ -104,6 +104,7 @@ config IA64_GENERIC
 
 config IA64_DIG
        bool "DIG-compliant"
+       select SWIOTLB
 
 config IA64_HP_ZX1
        bool "HP-zx1/sx1000"
@@ -113,6 +114,7 @@ config IA64_HP_ZX1
 
 config IA64_HP_ZX1_SWIOTLB
        bool "HP-zx1/sx1000 with software I/O TLB"
+       select SWIOTLB
        help
          Build a kernel that runs on HP zx1 and sx1000 systems even when they
          have broken PCI devices which cannot DMA to full 32 bits.  Apart
@@ -131,6 +133,7 @@ config IA64_SGI_SN2
 
 config IA64_HP_SIM
        bool "Ski-simulator"
+       select SWIOTLB
 
 endchoice
 
index a5a5637..2153bca 100644 (file)
@@ -192,3 +192,7 @@ EXPORT_SYMBOL(hwsw_unmap_sg);
 EXPORT_SYMBOL(hwsw_dma_supported);
 EXPORT_SYMBOL(hwsw_alloc_coherent);
 EXPORT_SYMBOL(hwsw_free_coherent);
+EXPORT_SYMBOL(hwsw_sync_single_for_cpu);
+EXPORT_SYMBOL(hwsw_sync_single_for_device);
+EXPORT_SYMBOL(hwsw_sync_sg_for_cpu);
+EXPORT_SYMBOL(hwsw_sync_sg_for_device);
index 29f05d4..9197d7b 100644 (file)
@@ -55,7 +55,7 @@
 
 #define BAD_MADT_ENTRY(entry, end) (                                        \
                (!entry) || (unsigned long)entry + sizeof(*entry) > end ||  \
-               ((acpi_table_entry_header *)entry)->length < sizeof(*entry))
+               ((struct acpi_subtable_header *)entry)->length < sizeof(*entry))
 
 #define PREFIX                 "ACPI: "
 
@@ -67,16 +67,11 @@ EXPORT_SYMBOL(pm_power_off);
 unsigned int acpi_cpei_override;
 unsigned int acpi_cpei_phys_cpuid;
 
-#define MAX_SAPICS 256
-u16 ia64_acpiid_to_sapicid[MAX_SAPICS] = {[0 ... MAX_SAPICS - 1] = -1 };
-
-EXPORT_SYMBOL(ia64_acpiid_to_sapicid);
-
 const char *acpi_get_sysname(void)
 {
 #ifdef CONFIG_IA64_GENERIC
        unsigned long rsdp_phys;
-       struct acpi20_table_rsdp *rsdp;
+       struct acpi_table_rsdp *rsdp;
        struct acpi_table_xsdt *xsdt;
        struct acpi_table_header *hdr;
 
@@ -87,16 +82,16 @@ const char *acpi_get_sysname(void)
                return "dig";
        }
 
-       rsdp = (struct acpi20_table_rsdp *)__va(rsdp_phys);
-       if (strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1)) {
+       rsdp = (struct acpi_table_rsdp *)__va(rsdp_phys);
+       if (strncmp(rsdp->signature, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)) {
                printk(KERN_ERR
                       "ACPI 2.0 RSDP signature incorrect, default to \"dig\"\n");
                return "dig";
        }
 
-       xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_address);
+       xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_physical_address);
        hdr = &xsdt->header;
-       if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1)) {
+       if (strncmp(hdr->signature, ACPI_SIG_XSDT, sizeof(ACPI_SIG_XSDT) - 1)) {
                printk(KERN_ERR
                       "ACPI 2.0 XSDT signature incorrect, default to \"dig\"\n");
                return "dig";
@@ -169,12 +164,12 @@ struct acpi_table_madt *acpi_madt __initdata;
 static u8 has_8259;
 
 static int __init
-acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header,
+acpi_parse_lapic_addr_ovr(struct acpi_subtable_header * header,
                          const unsigned long end)
 {
-       struct acpi_table_lapic_addr_ovr *lapic;
+       struct acpi_madt_local_apic_override *lapic;
 
-       lapic = (struct acpi_table_lapic_addr_ovr *)header;
+       lapic = (struct acpi_madt_local_apic_override *)header;
 
        if (BAD_MADT_ENTRY(lapic, end))
                return -EINVAL;
@@ -187,22 +182,19 @@ acpi_parse_lapic_addr_ovr(acpi_table_entry_header * header,
 }
 
 static int __init
-acpi_parse_lsapic(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_lsapic(struct acpi_subtable_header * header, const unsigned long end)
 {
-       struct acpi_table_lsapic *lsapic;
+       struct acpi_madt_local_sapic *lsapic;
 
-       lsapic = (struct acpi_table_lsapic *)header;
+       lsapic = (struct acpi_madt_local_sapic *)header;
 
-       if (BAD_MADT_ENTRY(lsapic, end))
-               return -EINVAL;
+       /*Skip BAD_MADT_ENTRY check, as lsapic size could vary */
 
-       if (lsapic->flags.enabled) {
+       if (lsapic->lapic_flags & ACPI_MADT_ENABLED) {
 #ifdef CONFIG_SMP
                smp_boot_data.cpu_phys_id[available_cpus] =
                    (lsapic->id << 8) | lsapic->eid;
 #endif
-               ia64_acpiid_to_sapicid[lsapic->acpi_id] =
-                   (lsapic->id << 8) | lsapic->eid;
                ++available_cpus;
        }
 
@@ -211,11 +203,11 @@ acpi_parse_lsapic(acpi_table_entry_header * header, const unsigned long end)
 }
 
 static int __init
-acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long end)
 {
-       struct acpi_table_lapic_nmi *lacpi_nmi;
+       struct acpi_madt_local_apic_nmi *lacpi_nmi;
 
-       lacpi_nmi = (struct acpi_table_lapic_nmi *)header;
+       lacpi_nmi = (struct acpi_madt_local_apic_nmi *)header;
 
        if (BAD_MADT_ENTRY(lacpi_nmi, end))
                return -EINVAL;
@@ -225,11 +217,11 @@ acpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end)
 }
 
 static int __init
-acpi_parse_iosapic(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_iosapic(struct acpi_subtable_header * header, const unsigned long end)
 {
-       struct acpi_table_iosapic *iosapic;
+       struct acpi_madt_io_sapic *iosapic;
 
-       iosapic = (struct acpi_table_iosapic *)header;
+       iosapic = (struct acpi_madt_io_sapic *)header;
 
        if (BAD_MADT_ENTRY(iosapic, end))
                return -EINVAL;
@@ -240,13 +232,13 @@ acpi_parse_iosapic(acpi_table_entry_header * header, const unsigned long end)
 static unsigned int __initdata acpi_madt_rev;
 
 static int __init
-acpi_parse_plat_int_src(acpi_table_entry_header * header,
+acpi_parse_plat_int_src(struct acpi_subtable_header * header,
                        const unsigned long end)
 {
-       struct acpi_table_plat_int_src *plintsrc;
+       struct acpi_madt_interrupt_source *plintsrc;
        int vector;
 
-       plintsrc = (struct acpi_table_plat_int_src *)header;
+       plintsrc = (struct acpi_madt_interrupt_source *)header;
 
        if (BAD_MADT_ENTRY(plintsrc, end))
                return -EINVAL;
@@ -257,19 +249,19 @@ acpi_parse_plat_int_src(acpi_table_entry_header * header,
         */
        vector = iosapic_register_platform_intr(plintsrc->type,
                                                plintsrc->global_irq,
-                                               plintsrc->iosapic_vector,
+                                               plintsrc->io_sapic_vector,
                                                plintsrc->eid,
                                                plintsrc->id,
-                                               (plintsrc->flags.polarity ==
-                                                1) ? IOSAPIC_POL_HIGH :
-                                               IOSAPIC_POL_LOW,
-                                               (plintsrc->flags.trigger ==
-                                                1) ? IOSAPIC_EDGE :
-                                               IOSAPIC_LEVEL);
+                                               ((plintsrc->inti_flags & ACPI_MADT_POLARITY_MASK) ==
+                                                ACPI_MADT_POLARITY_ACTIVE_HIGH) ?
+                                               IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
+                                               ((plintsrc->inti_flags & ACPI_MADT_TRIGGER_MASK) ==
+                                                ACPI_MADT_TRIGGER_EDGE) ?
+                                               IOSAPIC_EDGE : IOSAPIC_LEVEL);
 
        platform_intr_list[plintsrc->type] = vector;
        if (acpi_madt_rev > 1) {
-               acpi_cpei_override = plintsrc->plint_flags.cpei_override_flag;
+               acpi_cpei_override = plintsrc->flags & ACPI_MADT_CPEI_OVERRIDE;
        }
 
        /*
@@ -324,30 +316,32 @@ unsigned int get_cpei_target_cpu(void)
 }
 
 static int __init
-acpi_parse_int_src_ovr(acpi_table_entry_header * header,
+acpi_parse_int_src_ovr(struct acpi_subtable_header * header,
                       const unsigned long end)
 {
-       struct acpi_table_int_src_ovr *p;
+       struct acpi_madt_interrupt_override *p;
 
-       p = (struct acpi_table_int_src_ovr *)header;
+       p = (struct acpi_madt_interrupt_override *)header;
 
        if (BAD_MADT_ENTRY(p, end))
                return -EINVAL;
 
-       iosapic_override_isa_irq(p->bus_irq, p->global_irq,
-                                (p->flags.polarity ==
-                                 1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
-                                (p->flags.trigger ==
-                                 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
+       iosapic_override_isa_irq(p->source_irq, p->global_irq,
+                                ((p->inti_flags & ACPI_MADT_POLARITY_MASK) ==
+                                 ACPI_MADT_POLARITY_ACTIVE_HIGH) ?
+                                IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
+                                ((p->inti_flags & ACPI_MADT_TRIGGER_MASK) ==
+                                ACPI_MADT_TRIGGER_EDGE) ?
+                                IOSAPIC_EDGE : IOSAPIC_LEVEL);
        return 0;
 }
 
 static int __init
-acpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end)
+acpi_parse_nmi_src(struct acpi_subtable_header * header, const unsigned long end)
 {
-       struct acpi_table_nmi_src *nmi_src;
+       struct acpi_madt_nmi_source *nmi_src;
 
-       nmi_src = (struct acpi_table_nmi_src *)header;
+       nmi_src = (struct acpi_madt_nmi_source *)header;
 
        if (BAD_MADT_ENTRY(nmi_src, end))
                return -EINVAL;
@@ -371,12 +365,12 @@ static void __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
        }
 }
 
-static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_madt(struct acpi_table_header *table)
 {
-       if (!phys_addr || !size)
+       if (!table)
                return -EINVAL;
 
-       acpi_madt = (struct acpi_table_madt *)__va(phys_addr);
+       acpi_madt = (struct acpi_table_madt *)table;
 
        acpi_madt_rev = acpi_madt->header.revision;
 
@@ -384,14 +378,14 @@ static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size)
 #ifdef CONFIG_ITANIUM
        has_8259 = 1;           /* Firmware on old Itanium systems is broken */
 #else
-       has_8259 = acpi_madt->flags.pcat_compat;
+       has_8259 = acpi_madt->flags & ACPI_MADT_PCAT_COMPAT;
 #endif
        iosapic_system_init(has_8259);
 
        /* Get base address of IPI Message Block */
 
-       if (acpi_madt->lapic_address)
-               ipi_base_addr = ioremap(acpi_madt->lapic_address, 0);
+       if (acpi_madt->address)
+               ipi_base_addr = ioremap(acpi_madt->address, 0);
 
        printk(KERN_INFO PREFIX "Local APIC address %p\n", ipi_base_addr);
 
@@ -413,23 +407,24 @@ static u32 __devinitdata pxm_flag[PXM_FLAG_LEN];
 #define pxm_bit_test(bit)      (test_bit(bit,(void *)pxm_flag))
 static struct acpi_table_slit __initdata *slit_table;
 
-static int get_processor_proximity_domain(struct acpi_table_processor_affinity *pa)
+static int get_processor_proximity_domain(struct acpi_srat_cpu_affinity *pa)
 {
        int pxm;
 
-       pxm = pa->proximity_domain;
+       pxm = pa->proximity_domain_lo;
        if (ia64_platform_is("sn2"))
-               pxm += pa->reserved[0] << 8;
+               pxm += pa->proximity_domain_hi[0] << 8;
        return pxm;
 }
 
-static int get_memory_proximity_domain(struct acpi_table_memory_affinity *ma)
+static int get_memory_proximity_domain(struct acpi_srat_mem_affinity *ma)
 {
        int pxm;
 
        pxm = ma->proximity_domain;
-       if (ia64_platform_is("sn2"))
-               pxm += ma->reserved1[0] << 8;
+       if (!ia64_platform_is("sn2"))
+               pxm &= 0xff;
+
        return pxm;
 }
 
@@ -442,7 +437,7 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
        u32 len;
 
        len = sizeof(struct acpi_table_header) + 8
-           + slit->localities * slit->localities;
+           + slit->locality_count * slit->locality_count;
        if (slit->header.length != len) {
                printk(KERN_ERR
                       "ACPI 2.0 SLIT: size mismatch: %d expected, %d actual\n",
@@ -454,11 +449,11 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
 }
 
 void __init
-acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa)
+acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
 {
        int pxm;
 
-       if (!pa->flags.enabled)
+       if (!(pa->flags & ACPI_SRAT_CPU_ENABLED))
                return;
 
        pxm = get_processor_proximity_domain(pa);
@@ -467,14 +462,14 @@ acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa)
        pxm_bit_set(pxm);
 
        node_cpuid[srat_num_cpus].phys_id =
-           (pa->apic_id << 8) | (pa->lsapic_eid);
+           (pa->apic_id << 8) | (pa->local_sapic_eid);
        /* nid should be overridden as logical node id later */
        node_cpuid[srat_num_cpus].nid = pxm;
        srat_num_cpus++;
 }
 
 void __init
-acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
+acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 {
        unsigned long paddr, size;
        int pxm;
@@ -483,13 +478,11 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
        pxm = get_memory_proximity_domain(ma);
 
        /* fill node memory chunk structure */
-       paddr = ma->base_addr_hi;
-       paddr = (paddr << 32) | ma->base_addr_lo;
-       size = ma->length_hi;
-       size = (size << 32) | ma->length_lo;
+       paddr = ma->base_address;
+       size = ma->length;
 
        /* Ignore disabled entries */
-       if (!ma->flags.enabled)
+       if (!(ma->flags & ACPI_SRAT_MEM_ENABLED))
                return;
 
        /* record this node in proximity bitmap */
@@ -560,16 +553,16 @@ void __init acpi_numa_arch_fixup(void)
        if (!slit_table)
                return;
        memset(numa_slit, -1, sizeof(numa_slit));
-       for (i = 0; i < slit_table->localities; i++) {
+       for (i = 0; i < slit_table->locality_count; i++) {
                if (!pxm_bit_test(i))
                        continue;
                node_from = pxm_to_node(i);
-               for (j = 0; j < slit_table->localities; j++) {
+               for (j = 0; j < slit_table->locality_count; j++) {
                        if (!pxm_bit_test(j))
                                continue;
                        node_to = pxm_to_node(j);
                        node_distance(node_from, node_to) =
-                           slit_table->entry[i * slit_table->localities + j];
+                           slit_table->entry[i * slit_table->locality_count + j];
                }
        }
 
@@ -617,21 +610,21 @@ void acpi_unregister_gsi(u32 gsi)
 
 EXPORT_SYMBOL(acpi_unregister_gsi);
 
-static int __init acpi_parse_fadt(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_fadt(struct acpi_table_header *table)
 {
        struct acpi_table_header *fadt_header;
-       struct fadt_descriptor *fadt;
+       struct acpi_table_fadt *fadt;
 
-       if (!phys_addr || !size)
+       if (!table)
                return -EINVAL;
 
-       fadt_header = (struct acpi_table_header *)__va(phys_addr);
+       fadt_header = (struct acpi_table_header *)table;
        if (fadt_header->revision != 3)
                return -ENODEV; /* Only deal with ACPI 2.0 FADT */
 
-       fadt = (struct fadt_descriptor *)fadt_header;
+       fadt = (struct acpi_table_fadt *)fadt_header;
 
-       acpi_register_gsi(fadt->sci_int, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
+       acpi_register_gsi(fadt->sci_interrupt, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
        return 0;
 }
 
@@ -658,7 +651,7 @@ int __init acpi_boot_init(void)
         * information -- the successor to MPS tables.
         */
 
-       if (acpi_table_parse(ACPI_APIC, acpi_parse_madt) < 1) {
+       if (acpi_table_parse(ACPI_SIG_MADT, acpi_parse_madt) < 1) {
                printk(KERN_ERR PREFIX "Can't find MADT\n");
                goto skip_madt;
        }
@@ -666,40 +659,40 @@ int __init acpi_boot_init(void)
        /* Local APIC */
 
        if (acpi_table_parse_madt
-           (ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr, 0) < 0)
+           (ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE, acpi_parse_lapic_addr_ovr, 0) < 0)
                printk(KERN_ERR PREFIX
                       "Error parsing LAPIC address override entry\n");
 
-       if (acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic, NR_CPUS)
+       if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_SAPIC, acpi_parse_lsapic, NR_CPUS)
            < 1)
                printk(KERN_ERR PREFIX
                       "Error parsing MADT - no LAPIC entries\n");
 
-       if (acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi, 0)
+       if (acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0)
            < 0)
                printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");
 
        /* I/O APIC */
 
        if (acpi_table_parse_madt
-           (ACPI_MADT_IOSAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1)
+           (ACPI_MADT_TYPE_IO_SAPIC, acpi_parse_iosapic, NR_IOSAPICS) < 1)
                printk(KERN_ERR PREFIX
                       "Error parsing MADT - no IOSAPIC entries\n");
 
        /* System-Level Interrupt Routing */
 
        if (acpi_table_parse_madt
-           (ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src,
+           (ACPI_MADT_TYPE_INTERRUPT_SOURCE, acpi_parse_plat_int_src,
             ACPI_MAX_PLATFORM_INTERRUPTS) < 0)
                printk(KERN_ERR PREFIX
                       "Error parsing platform interrupt source entry\n");
 
        if (acpi_table_parse_madt
-           (ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr, 0) < 0)
+           (ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr, 0) < 0)
                printk(KERN_ERR PREFIX
                       "Error parsing interrupt source overrides entry\n");
 
-       if (acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src, 0) < 0)
+       if (acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src, 0) < 0)
                printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");
       skip_madt:
 
@@ -709,7 +702,7 @@ int __init acpi_boot_init(void)
         * gets interrupts such as power and sleep buttons.  If it's not
         * on a Legacy interrupt, it needs to be setup.
         */
-       if (acpi_table_parse(ACPI_FADT, acpi_parse_fadt) < 1)
+       if (acpi_table_parse(ACPI_SIG_FADT, acpi_parse_fadt) < 1)
                printk(KERN_ERR PREFIX "Can't find FADT\n");
 
 #ifdef CONFIG_SMP
@@ -842,7 +835,7 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
 {
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *obj;
-       struct acpi_table_lsapic *lsapic;
+       struct acpi_madt_local_sapic *lsapic;
        cpumask_t tmp_map;
        long physid;
        int cpu;
@@ -854,16 +847,16 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
                return -EINVAL;
 
        obj = buffer.pointer;
-       if (obj->type != ACPI_TYPE_BUFFER ||
-           obj->buffer.length < sizeof(*lsapic)) {
+       if (obj->type != ACPI_TYPE_BUFFER)
+       {
                kfree(buffer.pointer);
                return -EINVAL;
        }
 
-       lsapic = (struct acpi_table_lsapic *)obj->buffer.pointer;
+       lsapic = (struct acpi_madt_local_sapic *)obj->buffer.pointer;
 
-       if ((lsapic->header.type != ACPI_MADT_LSAPIC) ||
-           (!lsapic->flags.enabled)) {
+       if ((lsapic->header.type != ACPI_MADT_TYPE_LOCAL_SAPIC) ||
+           (!lsapic->lapic_flags & ACPI_MADT_ENABLED)) {
                kfree(buffer.pointer);
                return -EINVAL;
        }
@@ -883,7 +876,6 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu)
 
        cpu_set(cpu, cpu_present_map);
        ia64_cpu_to_sapicid[cpu] = physid;
-       ia64_acpiid_to_sapicid[lsapic->acpi_id] = ia64_cpu_to_sapicid[cpu];
 
        *pcpu = cpu;
        return (0);
@@ -893,14 +885,6 @@ EXPORT_SYMBOL(acpi_map_lsapic);
 
 int acpi_unmap_lsapic(int cpu)
 {
-       int i;
-
-       for (i = 0; i < MAX_SAPICS; i++) {
-               if (ia64_acpiid_to_sapicid[i] == ia64_cpu_to_sapicid[cpu]) {
-                       ia64_acpiid_to_sapicid[i] = -1;
-                       break;
-               }
-       }
        ia64_cpu_to_sapicid[cpu] = -1;
        cpu_clear(cpu, cpu_present_map);
 
@@ -920,7 +904,7 @@ acpi_map_iosapic(acpi_handle handle, u32 depth, void *context, void **ret)
 {
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *obj;
-       struct acpi_table_iosapic *iosapic;
+       struct acpi_madt_io_sapic *iosapic;
        unsigned int gsi_base;
        int pxm, node;
 
@@ -938,9 +922,9 @@ acpi_map_iosapic(acpi_handle handle, u32 depth, void *context, void **ret)
                return AE_OK;
        }
 
-       iosapic = (struct acpi_table_iosapic *)obj->buffer.pointer;
+       iosapic = (struct acpi_madt_io_sapic *)obj->buffer.pointer;
 
-       if (iosapic->header.type != ACPI_MADT_IOSAPIC) {
+       if (iosapic->header.type != ACPI_MADT_TYPE_IO_SAPIC) {
                kfree(buffer.pointer);
                return AE_OK;
        }
index bc2f64d..9d92097 100644 (file)
@@ -79,6 +79,7 @@ crash_save_this_cpu()
        final_note(buf);
 }
 
+#ifdef CONFIG_SMP
 static int
 kdump_wait_cpu_freeze(void)
 {
@@ -91,6 +92,7 @@ kdump_wait_cpu_freeze(void)
        }
        return 1;
 }
+#endif
 
 void
 machine_crash_shutdown(struct pt_regs *pt)
@@ -116,6 +118,11 @@ machine_crash_shutdown(struct pt_regs *pt)
 static void
 machine_kdump_on_init(void)
 {
+       if (!ia64_kimage) {
+               printk(KERN_NOTICE "machine_kdump_on_init(): "
+                               "kdump not configured\n");
+               return;
+       }
        local_irq_disable();
        kexec_disable_iosapic();
        machine_kexec(ia64_kimage);
@@ -132,11 +139,12 @@ kdump_cpu_freeze(struct unw_frame_info *info, void *arg)
        atomic_inc(&kdump_cpu_freezed);
        kdump_status[cpuid] = 1;
        mb();
-       if (cpuid == 0) {
-               for (;;)
-                       cpu_relax();
-       } else
+#ifdef CONFIG_HOTPLUG_CPU
+       if (cpuid != 0)
                ia64_jump_to_sal(&sal_boot_rendez_state[cpuid]);
+#endif
+       for (;;)
+               cpu_relax();
 }
 
 static int
index 83b8c91..da60e90 100644 (file)
@@ -9,7 +9,8 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 
-#include <linux/uaccess.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
 
 /**
  * copy_oldmem_page - copy one page from "oldmem"
index 0b25a7d..6c03928 100644 (file)
@@ -380,7 +380,7 @@ efi_get_pal_addr (void)
 #endif
                return __va(md->phys_addr);
        }
-       printk(KERN_WARNING "%s: no PAL-code memory-descriptor found",
+       printk(KERN_WARNING "%s: no PAL-code memory-descriptor found\n",
               __FUNCTION__);
        return NULL;
 }
index 15234ed..e7873ee 100644 (file)
@@ -1610,5 +1610,7 @@ sys_call_table:
        data8 sys_sync_file_range               // 1300
        data8 sys_tee
        data8 sys_vmsplice
+       data8 sys_ni_syscall                    // reserved for move_pages
+       data8 sys_getcpu
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
index 0fc5fb7..d6aab40 100644 (file)
@@ -925,6 +925,11 @@ iosapic_unregister_intr (unsigned int gsi)
                        /* Clear the interrupt controller descriptor */
                        idesc->chip = &no_irq_type;
 
+#ifdef CONFIG_SMP
+                       /* Clear affinity */
+                       cpus_setall(idesc->affinity);
+#endif
+
                        /* Clear the interrupt information */
                        memset(&iosapic_intr_info[vector], 0,
                               sizeof(struct iosapic_intr_info));
index e2ccc9f..4f0f3b8 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/kexec.h>
 #include <linux/cpu.h>
 #include <linux/irq.h>
+#include <linux/efi.h>
 #include <asm/mmu_context.h>
 #include <asm/setup.h>
 #include <asm/delay.h>
@@ -68,22 +69,10 @@ void machine_kexec_cleanup(struct kimage *image)
 {
 }
 
-void machine_shutdown(void)
-{
-       int cpu;
-
-       for_each_online_cpu(cpu) {
-               if (cpu != smp_processor_id())
-                       cpu_down(cpu);
-       }
-       kexec_disable_iosapic();
-}
-
 /*
  * Do not allocate memory (or fail in any way) in machine_kexec().
  * We are past the point of no return, committed to rebooting now.
  */
-extern void *efi_get_pal_addr(void);
 static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
 {
        struct kimage *image = arg;
@@ -93,6 +82,7 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
        unsigned long vector;
        int ii;
 
+       BUG_ON(!image);
        if (image->type == KEXEC_TYPE_CRASH) {
                crash_save_this_cpu();
                current->thread.ksp = (__u64)info->sw - 16;
@@ -131,6 +121,7 @@ static void ia64_machine_kexec(struct unw_frame_info *info, void *arg)
 
 void machine_kexec(struct kimage *image)
 {
+       BUG_ON(!image);
        unw_init_running(ia64_machine_kexec, image);
        for(;;);
 }
index 822e59a..0d05450 100644 (file)
@@ -64,12 +64,17 @@ static void ia64_set_msi_irq_affinity(unsigned int irq, cpumask_t cpu_mask)
 }
 #endif /* CONFIG_SMP */
 
-int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 {
        struct msi_msg  msg;
        unsigned long   dest_phys_id;
-       unsigned int    vector;
+       unsigned int    irq, vector;
 
+       irq = create_irq();
+       if (irq < 0)
+               return irq;
+
+       set_irq_msi(irq, desc);
        dest_phys_id = cpu_physical_id(first_cpu(cpu_online_map));
        vector = irq;
 
@@ -89,12 +94,12 @@ int ia64_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
        write_msi_msg(irq, &msg);
        set_irq_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
 
-       return 0;
+       return irq;
 }
 
 void ia64_teardown_msi_irq(unsigned int irq)
 {
-       return;         /* no-op */
+       destroy_irq(irq);
 }
 
 static void ia64_ack_msi_irq(unsigned int irq)
@@ -126,12 +131,12 @@ static struct irq_chip ia64_msi_chip = {
 };
 
 
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
 {
        if (platform_setup_msi_irq)
-               return platform_setup_msi_irq(irq, pdev);
+               return platform_setup_msi_irq(pdev, desc);
 
-       return ia64_setup_msi_irq(irq, pdev);
+       return ia64_setup_msi_irq(pdev, desc);
 }
 
 void arch_teardown_msi_irq(unsigned int irq)
index 17685ab..ae96d41 100644 (file)
@@ -34,6 +34,7 @@
 #include <asm/ia32.h>
 #include <asm/irq.h>
 #include <asm/kdebug.h>
+#include <asm/kexec.h>
 #include <asm/pgalloc.h>
 #include <asm/processor.h>
 #include <asm/sal.h>
@@ -803,6 +804,21 @@ cpu_halt (void)
                ia64_pal_halt(min_power_state);
 }
 
+void machine_shutdown(void)
+{
+#ifdef CONFIG_HOTPLUG_CPU
+       int cpu;
+
+       for_each_online_cpu(cpu) {
+               if (cpu != smp_processor_id())
+                       cpu_down(cpu);
+       }
+#endif
+#ifdef CONFIG_KEXEC
+       kexec_disable_iosapic();
+#endif
+}
+
 void
 machine_restart (char *restart_cmd)
 {
index aa705e4..3f89187 100644 (file)
@@ -607,7 +607,7 @@ find_thread_for_addr (struct task_struct *child, unsigned long addr)
         */
        list_for_each_safe(this, next, &current->children) {
                p = list_entry(this, struct task_struct, sibling);
-               if (p->mm != mm)
+               if (p->tgid != child->tgid)
                        continue;
                if (thread_matches(p, addr)) {
                        child = p;
@@ -1405,6 +1405,7 @@ ptrace_disable (struct task_struct *child)
        struct ia64_psr *child_psr = ia64_psr(task_pt_regs(child));
 
        /* make sure the single step/taken-branch trap bits are not set: */
+       clear_tsk_thread_flag(child, TIF_SINGLESTEP);
        child_psr->ss = 0;
        child_psr->tb = 0;
 }
@@ -1525,6 +1526,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
                 * Make sure the single step/taken-branch trap bits
                 * are not set:
                 */
+               clear_tsk_thread_flag(child, TIF_SINGLESTEP);
                ia64_psr(pt)->ss = 0;
                ia64_psr(pt)->tb = 0;
 
@@ -1556,6 +1558,7 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
                        goto out_tsk;
 
                clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+               set_tsk_thread_flag(child, TIF_SINGLESTEP);
                if (request == PTRACE_SINGLESTEP) {
                        ia64_psr(pt)->ss = 1;
                } else {
@@ -1595,13 +1598,9 @@ sys_ptrace (long request, pid_t pid, unsigned long addr, unsigned long data)
 }
 
 
-void
+static void
 syscall_trace (void)
 {
-       if (!test_thread_flag(TIF_SYSCALL_TRACE))
-               return;
-       if (!(current->ptrace & PT_PTRACED))
-               return;
        /*
         * The 0x80 provides a way for the tracing parent to
         * distinguish between a syscall stop and SIGTRAP delivery.
@@ -1664,7 +1663,8 @@ syscall_trace_leave (long arg0, long arg1, long arg2, long arg3,
                audit_syscall_exit(success, result);
        }
 
-       if (test_thread_flag(TIF_SYSCALL_TRACE)
+       if ((test_thread_flag(TIF_SYSCALL_TRACE)
+           || test_thread_flag(TIF_SINGLESTEP))
            && (current->ptrace & PT_PTRACED))
                syscall_trace();
 }
index ad567b8..83c2629 100644 (file)
@@ -569,34 +569,31 @@ show_cpuinfo (struct seq_file *m, void *v)
                { 1UL << 1, "spontaneous deferral"},
                { 1UL << 2, "16-byte atomic ops" }
        };
-       char features[128], *cp, sep;
+       char features[128], *cp, *sep;
        struct cpuinfo_ia64 *c = v;
        unsigned long mask;
        unsigned long proc_freq;
-       int i;
+       int i, size;
 
        mask = c->features;
 
        /* build the feature string: */
-       memcpy(features, " standard", 10);
+       memcpy(features, "standard", 9);
        cp = features;
-       sep = 0;
-       for (i = 0; i < (int) ARRAY_SIZE(feature_bits); ++i) {
+       size = sizeof(features);
+       sep = "";
+       for (i = 0; i < ARRAY_SIZE(feature_bits) && size > 1; ++i) {
                if (mask & feature_bits[i].mask) {
-                       if (sep)
-                               *cp++ = sep;
-                       sep = ',';
-                       *cp++ = ' ';
-                       strcpy(cp, feature_bits[i].feature_name);
-                       cp += strlen(feature_bits[i].feature_name);
+                       cp += snprintf(cp, size, "%s%s", sep,
+                                      feature_bits[i].feature_name),
+                       sep = ", ";
                        mask &= ~feature_bits[i].mask;
+                       size = sizeof(features) - (cp - features);
                }
        }
-       if (mask) {
-               /* print unknown features as a hex value: */
-               if (sep)
-                       *cp++ = sep;
-               sprintf(cp, " 0x%lx", mask);
+       if (mask && size > 1) {
+               /* print unknown features as a hex value */
+               snprintf(cp, size, "%s0x%lx", sep, mask);
        }
 
        proc_freq = cpufreq_quick_get(cpunum);
@@ -612,7 +609,7 @@ show_cpuinfo (struct seq_file *m, void *v)
                   "model name : %s\n"
                   "revision   : %u\n"
                   "archrev    : %u\n"
-                  "features   :%s\n"   /* don't change this---it _is_ right! */
+                  "features   : %s\n"
                   "cpu number : %lu\n"
                   "cpu regs   : %u\n"
                   "cpu MHz    : %lu.%06lu\n"
index d6083a0..8f3d006 100644 (file)
@@ -157,6 +157,7 @@ SECTIONS
        }
 #endif
 
+  . = ALIGN(8);
    __con_initcall_start = .;
   .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET)
        { *(.con_initcall.init) }
index 1e79551..63e6d49 100644 (file)
@@ -30,47 +30,69 @@ static unsigned long max_gap;
 #endif
 
 /**
- * show_mem - display a memory statistics summary
+ * show_mem - give short summary of memory stats
  *
- * Just walks the pages in the system and describes where they're allocated.
+ * Shows a simple page count of reserved and used pages in the system.
+ * For discontig machines, it does this on a per-pgdat basis.
  */
-void
-show_mem (void)
+void show_mem(void)
 {
-       int i, total = 0, reserved = 0;
-       int shared = 0, cached = 0;
+       int i, total_reserved = 0;
+       int total_shared = 0, total_cached = 0;
+       unsigned long total_present = 0;
+       pg_data_t *pgdat;
 
        printk(KERN_INFO "Mem-info:\n");
        show_free_areas();
-
        printk(KERN_INFO "Free swap:       %6ldkB\n",
               nr_swap_pages<<(PAGE_SHIFT-10));
-       i = max_mapnr;
-       for (i = 0; i < max_mapnr; i++) {
-               if (!pfn_valid(i)) {
+       printk(KERN_INFO "Node memory in pages:\n");
+       for_each_online_pgdat(pgdat) {
+               unsigned long present;
+               unsigned long flags;
+               int shared = 0, cached = 0, reserved = 0;
+
+               pgdat_resize_lock(pgdat, &flags);
+               present = pgdat->node_present_pages;
+               for(i = 0; i < pgdat->node_spanned_pages; i++) {
+                       struct page *page;
+                       if (pfn_valid(pgdat->node_start_pfn + i))
+                               page = pfn_to_page(pgdat->node_start_pfn + i);
+                       else {
 #ifdef CONFIG_VIRTUAL_MEM_MAP
-                       if (max_gap < LARGE_GAP)
-                               continue;
-                       i = vmemmap_find_next_valid_pfn(0, i) - 1;
+                               if (max_gap < LARGE_GAP)
+                                       continue;
 #endif
-                       continue;
+                               i = vmemmap_find_next_valid_pfn(pgdat->node_id,
+                                        i) - 1;
+                               continue;
+                       }
+                       if (PageReserved(page))
+                               reserved++;
+                       else if (PageSwapCache(page))
+                               cached++;
+                       else if (page_count(page))
+                               shared += page_count(page)-1;
                }
-               total++;
-               if (PageReserved(mem_map+i))
-                       reserved++;
-               else if (PageSwapCache(mem_map+i))
-                       cached++;
-               else if (page_count(mem_map + i))
-                       shared += page_count(mem_map + i) - 1;
+               pgdat_resize_unlock(pgdat, &flags);
+               total_present += present;
+               total_reserved += reserved;
+               total_cached += cached;
+               total_shared += shared;
+               printk(KERN_INFO "Node %4d:  RAM: %11ld, rsvd: %8d, "
+                      "shrd: %10d, swpd: %10d\n", pgdat->node_id,
+                      present, reserved, shared, cached);
        }
-       printk(KERN_INFO "%d pages of RAM\n", total);
-       printk(KERN_INFO "%d reserved pages\n", reserved);
-       printk(KERN_INFO "%d pages shared\n", shared);
-       printk(KERN_INFO "%d pages swap cached\n", cached);
-       printk(KERN_INFO "%ld pages in page table cache\n",
+       printk(KERN_INFO "%ld pages of RAM\n", total_present);
+       printk(KERN_INFO "%d reserved pages\n", total_reserved);
+       printk(KERN_INFO "%d pages shared\n", total_shared);
+       printk(KERN_INFO "%d pages swap cached\n", total_cached);
+       printk(KERN_INFO "Total of %ld pages in page table cache\n",
               pgtable_quicklist_total_size());
+       printk(KERN_INFO "%d free buffer pages\n", nr_free_buffer_pages());
 }
 
+
 /* physical address where the bootmem map is located */
 unsigned long bootmap_start;
 
@@ -177,7 +199,7 @@ find_memory (void)
 
 #ifdef CONFIG_CRASH_DUMP
        /* If we are doing a crash dump, we still need to know the real mem
-        * size before original memory map is reset. */
+        * size before original memory map is reset. */
        saved_max_pfn = max_pfn;
 #endif
 }
index 96722cb..6eae596 100644 (file)
@@ -412,37 +412,6 @@ static void __init memory_less_nodes(void)
        return;
 }
 
-#ifdef CONFIG_SPARSEMEM
-/**
- * register_sparse_mem - notify SPARSEMEM that this memory range exists.
- * @start: physical start of range
- * @end: physical end of range
- * @arg: unused
- *
- * Simply calls SPARSEMEM to register memory section(s).
- */
-static int __init register_sparse_mem(unsigned long start, unsigned long end,
-       void *arg)
-{
-       int nid;
-
-       start = __pa(start) >> PAGE_SHIFT;
-       end = __pa(end) >> PAGE_SHIFT;
-       nid = early_pfn_to_nid(start);
-       memory_present(nid, start, end);
-
-       return 0;
-}
-
-static void __init arch_sparse_init(void)
-{
-       efi_memmap_walk(register_sparse_mem, NULL);
-       sparse_init();
-}
-#else
-#define arch_sparse_init() do {} while (0)
-#endif
-
 /**
  * find_memory - walk the EFI memory map and setup the bootmem allocator
  *
@@ -473,6 +442,9 @@ void __init find_memory(void)
                        node_clear(node, memory_less_mask);
                        mem_data[node].min_pfn = ~0UL;
                }
+
+       efi_memmap_walk(register_active_ranges, NULL);
+
        /*
         * Initialize the boot memory maps in reverse order since that's
         * what the bootmem allocator expects
@@ -506,6 +478,12 @@ void __init find_memory(void)
        max_pfn = max_low_pfn;
 
        find_initrd();
+
+#ifdef CONFIG_CRASH_DUMP
+       /* If we are doing a crash dump, we still need to know the real mem
+        * size before original memory map is reset. */
+        saved_max_pfn = max_pfn;
+#endif
 }
 
 #ifdef CONFIG_SMP
@@ -654,7 +632,6 @@ static __init int count_node_pages(unsigned long start, unsigned long len, int n
 {
        unsigned long end = start + len;
 
-       add_active_range(node, start >> PAGE_SHIFT, end >> PAGE_SHIFT);
        mem_data[node].num_physpages += len >> PAGE_SHIFT;
        if (start <= __pa(MAX_DMA_ADDRESS))
                mem_data[node].num_dma_physpages +=
@@ -686,10 +663,11 @@ void __init paging_init(void)
 
        max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
 
-       arch_sparse_init();
-
        efi_memmap_walk(filter_rsvd_memory, count_node_pages);
 
+       sparse_memory_present_with_active_regions(MAX_NUMNODES);
+       sparse_init();
+
 #ifdef CONFIG_VIRTUAL_MEM_MAP
        vmalloc_end -= PAGE_ALIGN(ALIGN(max_low_pfn, MAX_ORDER_NR_PAGES) *
                sizeof(struct page));
index 1373fae..faaca21 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/swap.h>
 #include <linux/proc_fs.h>
 #include <linux/bitops.h>
+#include <linux/kexec.h>
 
 #include <asm/a.out.h>
 #include <asm/dma.h>
@@ -128,6 +129,25 @@ lazy_mmu_prot_update (pte_t pte)
        set_bit(PG_arch_1, &page->flags);       /* mark page as clean */
 }
 
+/*
+ * Since DMA is i-cache coherent, any (complete) pages that were written via
+ * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
+ * flush them when they get mapped into an executable vm-area.
+ */
+void
+dma_mark_clean(void *addr, size_t size)
+{
+       unsigned long pg_addr, end;
+
+       pg_addr = PAGE_ALIGN((unsigned long) addr);
+       end = (unsigned long) addr + size;
+       while (pg_addr + PAGE_SIZE <= end) {
+               struct page *page = virt_to_page(pg_addr);
+               set_bit(PG_arch_1, &page->flags);
+               pg_addr += PAGE_SIZE;
+       }
+}
+
 inline void
 ia64_set_rbs_bot (void)
 {
@@ -595,13 +615,27 @@ find_largest_hole (u64 start, u64 end, void *arg)
        return 0;
 }
 
+#endif /* CONFIG_VIRTUAL_MEM_MAP */
+
 int __init
 register_active_ranges(u64 start, u64 end, void *arg)
 {
-       add_active_range(0, __pa(start) >> PAGE_SHIFT, __pa(end) >> PAGE_SHIFT);
+       int nid = paddr_to_nid(__pa(start));
+
+       if (nid < 0)
+               nid = 0;
+#ifdef CONFIG_KEXEC
+       if (start > crashk_res.start && start < crashk_res.end)
+               start = crashk_res.end;
+       if (end > crashk_res.start && end < crashk_res.end)
+               end = crashk_res.start;
+#endif
+
+       if (start < end)
+               add_active_range(nid, __pa(start) >> PAGE_SHIFT,
+                       __pa(end) >> PAGE_SHIFT);
        return 0;
 }
-#endif /* CONFIG_VIRTUAL_MEM_MAP */
 
 static int __init
 count_reserved_pages (u64 start, u64 end, void *arg)
index abca6bd..fcf7f93 100644 (file)
@@ -3,7 +3,7 @@
  * License.  See the file "COPYING" in the main directory of this archive
  * for more details.
  *
- * Copyright (C) 1992 - 1997, 2000,2002-2005 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 1992 - 1997, 2000,2002-2007 Silicon Graphics, Inc. All rights reserved.
  */
 
 #include <linux/types.h>
@@ -38,12 +38,20 @@ static irqreturn_t hub_eint_handler(int irq, void *arg)
                        (u64) nasid, 0, 0, 0, 0, 0, 0);
 
                if ((int)ret_stuff.v0)
-                       panic("hubii_eint_handler(): Fatal TIO Error");
+                       panic("%s: Fatal %s Error", __FUNCTION__,
+                               ((nasid & 1) ? "TIO" : "HUBII"));
 
                if (!(nasid & 1)) /* Not a TIO, handle CRB errors */
                        (void)hubiio_crb_error_handler(hubdev_info);
-       } else 
-               bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid)));
+       } else
+               if (nasid & 1) {        /* TIO errors */
+                       SAL_CALL_NOLOCK(ret_stuff, SN_SAL_HUB_ERROR_INTERRUPT,
+                               (u64) nasid, 0, 0, 0, 0, 0, 0);
+
+                       if ((int)ret_stuff.v0)
+                               panic("%s: Fatal TIO Error", __FUNCTION__);
+               } else
+                       bte_error_handler((unsigned long)NODEPDA(nasid_to_cnodeid(nasid)));
 
        return IRQ_HANDLED;
 }
index cb96b4e..8c331ca 100644 (file)
@@ -13,6 +13,7 @@
 #include <asm/sn/sn_sal.h>
 #include "xtalk/hubdev.h"
 #include <linux/acpi.h>
+#include <acpi/acnamesp.h>
 
 
 /*
@@ -31,6 +32,12 @@ struct acpi_vendor_uuid sn_uuid = {
                    0xa2, 0x7c, 0x08, 0x00, 0x69, 0x13, 0xea, 0x51 },
 };
 
+struct sn_pcidev_match {
+       u8 bus;
+       unsigned int devfn;
+       acpi_handle handle;
+};
+
 /*
  * Perform the early IO init in PROM.
  */
@@ -119,9 +126,11 @@ sn_get_bussoft_ptr(struct pci_bus *bus)
        status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS,
                                          &sn_uuid, &buffer);
        if (ACPI_FAILURE(status)) {
-               printk(KERN_ERR "get_acpi_pcibus_ptr: "
-                      "get_acpi_bussoft_info() failed: %d\n",
-                      status);
+               printk(KERN_ERR "%s: "
+                      "acpi_get_vendor_resource() failed (0x%x) for: ",
+                      __FUNCTION__, status);
+               acpi_ns_print_node_pathname(handle, NULL);
+               printk("\n");
                return NULL;
        }
        resource = buffer.pointer;
@@ -130,8 +139,8 @@ sn_get_bussoft_ptr(struct pci_bus *bus)
        if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) !=
             sizeof(struct pcibus_bussoft *)) {
                printk(KERN_ERR
-                      "get_acpi_bussoft_ptr: Invalid vendor data "
-                      "length %d\n", vendor->byte_length);
+                      "%s: Invalid vendor data length %d\n",
+                       __FUNCTION__, vendor->byte_length);
                kfree(buffer.pointer);
                return NULL;
        }
@@ -143,34 +152,254 @@ sn_get_bussoft_ptr(struct pci_bus *bus)
 }
 
 /*
- * sn_acpi_bus_fixup
+ * sn_extract_device_info - Extract the pcidev_info and the sn_irq_info
+ *                         pointers from the vendor resource using the
+ *                         provided acpi handle, and copy the structures
+ *                         into the argument buffers.
  */
-void
-sn_acpi_bus_fixup(struct pci_bus *bus)
+static int
+sn_extract_device_info(acpi_handle handle, struct pcidev_info **pcidev_info,
+                   struct sn_irq_info **sn_irq_info)
 {
-       struct pci_dev *pci_dev = NULL;
-       struct pcibus_bussoft *prom_bussoft_ptr;
-       extern void sn_common_bus_fixup(struct pci_bus *,
-                                       struct pcibus_bussoft *);
+       u64 addr;
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct sn_irq_info *irq_info, *irq_info_prom;
+       struct pcidev_info *pcidev_ptr, *pcidev_prom_ptr;
+       struct acpi_resource *resource;
+       int ret = 0;
+       acpi_status status;
+       struct acpi_resource_vendor_typed *vendor;
 
-       if (!bus->parent) {     /* If root bus */
-               prom_bussoft_ptr = sn_get_bussoft_ptr(bus);
-               if (prom_bussoft_ptr == NULL) {
+       /*
+        * The pointer to this device's pcidev_info structure in
+        * the PROM, is in the vendor resource.
+        */
+       status = acpi_get_vendor_resource(handle, METHOD_NAME__CRS,
+                                         &sn_uuid, &buffer);
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_ERR
+                      "%s: acpi_get_vendor_resource() failed (0x%x) for: ",
+                       __FUNCTION__, status);
+               acpi_ns_print_node_pathname(handle, NULL);
+               printk("\n");
+               return 1;
+       }
+
+       resource = buffer.pointer;
+       vendor = &resource->data.vendor_typed;
+       if ((vendor->byte_length - sizeof(struct acpi_vendor_uuid)) !=
+           sizeof(struct pci_devdev_info *)) {
+               printk(KERN_ERR
+                      "%s: Invalid vendor data length: %d for: ",
+                       __FUNCTION__, vendor->byte_length);
+               acpi_ns_print_node_pathname(handle, NULL);
+               printk("\n");
+               ret = 1;
+               goto exit;
+       }
+
+       pcidev_ptr = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
+       if (!pcidev_ptr)
+               panic("%s: Unable to alloc memory for pcidev_info", __FUNCTION__);
+
+       memcpy(&addr, vendor->byte_data, sizeof(struct pcidev_info *));
+       pcidev_prom_ptr = __va(addr);
+       memcpy(pcidev_ptr, pcidev_prom_ptr, sizeof(struct pcidev_info));
+
+       /* Get the IRQ info */
+       irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
+       if (!irq_info)
+                panic("%s: Unable to alloc memory for sn_irq_info", __FUNCTION__);
+
+       if (pcidev_ptr->pdi_sn_irq_info) {
+               irq_info_prom = __va(pcidev_ptr->pdi_sn_irq_info);
+               memcpy(irq_info, irq_info_prom, sizeof(struct sn_irq_info));
+       }
+
+       *pcidev_info = pcidev_ptr;
+       *sn_irq_info = irq_info;
+
+exit:
+       kfree(buffer.pointer);
+       return ret;
+}
+
+static unsigned int
+get_host_devfn(acpi_handle device_handle, acpi_handle rootbus_handle)
+{
+       unsigned long adr;
+       acpi_handle child;
+       unsigned int devfn;
+       int function;
+       acpi_handle parent;
+       int slot;
+       acpi_status status;
+
+       /*
+        * Do an upward search to find the root bus device, and
+        * obtain the host devfn from the previous child device.
+        */
+       child = device_handle;
+       while (child) {
+               status = acpi_get_parent(child, &parent);
+               if (ACPI_FAILURE(status)) {
+                       printk(KERN_ERR "%s: acpi_get_parent() failed "
+                              "(0x%x) for: ", __FUNCTION__, status);
+                       acpi_ns_print_node_pathname(child, NULL);
+                       printk("\n");
+                       panic("%s: Unable to find host devfn\n", __FUNCTION__);
+               }
+               if (parent == rootbus_handle)
+                       break;
+               child = parent;
+       }
+       if (!child) {
+               printk(KERN_ERR "%s: Unable to find root bus for: ",
+                      __FUNCTION__);
+               acpi_ns_print_node_pathname(device_handle, NULL);
+               printk("\n");
+               BUG();
+       }
+
+       status = acpi_evaluate_integer(child, METHOD_NAME__ADR, NULL, &adr);
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_ERR "%s: Unable to get _ADR (0x%x) for: ",
+                      __FUNCTION__, status);
+               acpi_ns_print_node_pathname(child, NULL);
+               printk("\n");
+               panic("%s: Unable to find host devfn\n", __FUNCTION__);
+       }
+
+       slot = (adr >> 16) & 0xffff;
+       function = adr & 0xffff;
+       devfn = PCI_DEVFN(slot, function);
+       return devfn;
+}
+
+/*
+ * find_matching_device - Callback routine to find the ACPI device
+ *                       that matches up with our pci_dev device.
+ *                       Matching is done on bus number and devfn.
+ *                       To find the bus number for a particular
+ *                       ACPI device, we must look at the _BBN method
+ *                       of its parent.
+ */
+static acpi_status
+find_matching_device(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+       unsigned long bbn = -1;
+       unsigned long adr;
+       acpi_handle parent = NULL;
+       acpi_status status;
+       unsigned int devfn;
+       int function;
+       int slot;
+       struct sn_pcidev_match *info = context;
+
+        status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
+                                       &adr);
+        if (ACPI_SUCCESS(status)) {
+               status = acpi_get_parent(handle, &parent);
+               if (ACPI_FAILURE(status)) {
                        printk(KERN_ERR
-                              "sn_pci_fixup_bus: 0x%04x:0x%02x Unable to "
-                              "obtain prom_bussoft_ptr\n",
-                              pci_domain_nr(bus), bus->number);
-                       return;
+                              "%s: acpi_get_parent() failed (0x%x) for: ",
+                                       __FUNCTION__, status);
+                       acpi_ns_print_node_pathname(handle, NULL);
+                       printk("\n");
+                       return AE_OK;
+               }
+               status = acpi_evaluate_integer(parent, METHOD_NAME__BBN,
+                                              NULL, &bbn);
+               if (ACPI_FAILURE(status)) {
+                       printk(KERN_ERR
+                         "%s: Failed to find _BBN in parent of: ",
+                                       __FUNCTION__);
+                       acpi_ns_print_node_pathname(handle, NULL);
+                       printk("\n");
+                       return AE_OK;
+               }
+
+                slot = (adr >> 16) & 0xffff;
+                function = adr & 0xffff;
+                devfn = PCI_DEVFN(slot, function);
+                if ((info->devfn == devfn) && (info->bus == bbn)) {
+                       /* We have a match! */
+                       info->handle = handle;
+                       return 1;
                }
-               sn_common_bus_fixup(bus, prom_bussoft_ptr);
        }
-       list_for_each_entry(pci_dev, &bus->devices, bus_list) {
-               sn_pci_fixup_slot(pci_dev);
+       return AE_OK;
+}
+
+/*
+ * sn_acpi_get_pcidev_info - Search ACPI namespace for the acpi
+ *                          device matching the specified pci_dev,
+ *                          and return the pcidev info and irq info.
+ */
+int
+sn_acpi_get_pcidev_info(struct pci_dev *dev, struct pcidev_info **pcidev_info,
+                       struct sn_irq_info **sn_irq_info)
+{
+       unsigned int host_devfn;
+       struct sn_pcidev_match pcidev_match;
+       acpi_handle rootbus_handle;
+       unsigned long segment;
+       acpi_status status;
+
+       rootbus_handle = PCI_CONTROLLER(dev)->acpi_handle;
+        status = acpi_evaluate_integer(rootbus_handle, METHOD_NAME__SEG, NULL,
+                                       &segment);
+        if (ACPI_SUCCESS(status)) {
+               if (segment != pci_domain_nr(dev)) {
+                       printk(KERN_ERR
+                              "%s: Segment number mismatch, 0x%lx vs 0x%x for: ",
+                              __FUNCTION__, segment, pci_domain_nr(dev));
+                       acpi_ns_print_node_pathname(rootbus_handle, NULL);
+                       printk("\n");
+                       return 1;
+               }
+       } else {
+               printk(KERN_ERR "%s: Unable to get __SEG from: ",
+                      __FUNCTION__);
+               acpi_ns_print_node_pathname(rootbus_handle, NULL);
+               printk("\n");
+               return 1;
+       }
+
+       /*
+        * We want to search all devices in this segment/domain
+        * of the ACPI namespace for the matching ACPI device,
+        * which holds the pcidev_info pointer in its vendor resource.
+        */
+       pcidev_match.bus = dev->bus->number;
+       pcidev_match.devfn = dev->devfn;
+       pcidev_match.handle = NULL;
+
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, rootbus_handle, ACPI_UINT32_MAX,
+                           find_matching_device, &pcidev_match, NULL);
+
+       if (!pcidev_match.handle) {
+               printk(KERN_ERR
+                      "%s: Could not find matching ACPI device for %s.\n",
+                      __FUNCTION__, pci_name(dev));
+               return 1;
        }
+
+       if (sn_extract_device_info(pcidev_match.handle, pcidev_info, sn_irq_info))
+               return 1;
+
+       /* Build up the pcidev_info.pdi_slot_host_handle */
+       host_devfn = get_host_devfn(pcidev_match.handle, rootbus_handle);
+       (*pcidev_info)->pdi_slot_host_handle =
+                       ((unsigned long) pci_domain_nr(dev) << 40) |
+                                       /* bus == 0 */
+                                       host_devfn;
+       return 0;
 }
 
 /*
- * sn_acpi_slot_fixup - Perform any SN specific slot fixup.
+ * sn_acpi_slot_fixup - Obtain the pcidev_info and sn_irq_info.
+ *                     Perform any SN specific slot fixup.
  *                     At present there does not appear to be
  *                     any generic way to handle a ROM image
  *                     that has been shadowed by the PROM, so
@@ -179,11 +408,18 @@ sn_acpi_bus_fixup(struct pci_bus *bus)
  */
 
 void
-sn_acpi_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
+sn_acpi_slot_fixup(struct pci_dev *dev)
 {
        void __iomem *addr;
+       struct pcidev_info *pcidev_info = NULL;
+       struct sn_irq_info *sn_irq_info = NULL;
        size_t size;
 
+       if (sn_acpi_get_pcidev_info(dev, &pcidev_info, &sn_irq_info)) {
+               panic("%s:  Failure obtaining pcidev_info for %s\n",
+                     __FUNCTION__, pci_name(dev));
+       }
+
        if (pcidev_info->pdi_pio_mapped_addr[PCI_ROM_RESOURCE]) {
                /*
                 * A valid ROM image exists and has been shadowed by the
@@ -200,8 +436,11 @@ sn_acpi_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
                                                (unsigned long) addr + size;
                dev->resource[PCI_ROM_RESOURCE].flags |= IORESOURCE_ROM_BIOS_COPY;
        }
+       sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
 }
 
+EXPORT_SYMBOL(sn_acpi_slot_fixup);
+
 static struct acpi_driver acpi_sn_hubdev_driver = {
        .name = "SGI HUBDEV Driver",
        .ids = "SGIHUB,SGITIO",
@@ -211,6 +450,33 @@ static struct acpi_driver acpi_sn_hubdev_driver = {
 };
 
 
+/*
+ * sn_acpi_bus_fixup -  Perform SN specific setup of software structs
+ *                     (pcibus_bussoft, pcidev_info) and hardware
+ *                     registers, for the specified bus and devices under it.
+ */
+void
+sn_acpi_bus_fixup(struct pci_bus *bus)
+{
+       struct pci_dev *pci_dev = NULL;
+       struct pcibus_bussoft *prom_bussoft_ptr;
+
+       if (!bus->parent) {     /* If root bus */
+               prom_bussoft_ptr = sn_get_bussoft_ptr(bus);
+               if (prom_bussoft_ptr == NULL) {
+                       printk(KERN_ERR
+                              "%s: 0x%04x:0x%02x Unable to "
+                              "obtain prom_bussoft_ptr\n",
+                              __FUNCTION__, pci_domain_nr(bus), bus->number);
+                       return;
+               }
+               sn_common_bus_fixup(bus, prom_bussoft_ptr);
+       }
+       list_for_each_entry(pci_dev, &bus->devices, bus_list) {
+               sn_acpi_slot_fixup(pci_dev);
+       }
+}
+
 /*
  * sn_io_acpi_init - PROM has ACPI support for IO, defining at a minimum the
  *                  nodes and root buses in the DSDT. As a result, bus scanning
index d4dd8f4..d48bcd8 100644 (file)
 #include <linux/acpi.h>
 #include <asm/sn/sn2/sn_hwperf.h>
 #include <asm/sn/acpi.h>
+#include "acpi/acglobal.h"
 
 extern void sn_init_cpei_timer(void);
 extern void register_sn_procfs(void);
-extern void sn_acpi_bus_fixup(struct pci_bus *);
-extern void sn_bus_fixup(struct pci_bus *);
-extern void sn_acpi_slot_fixup(struct pci_dev *, struct pcidev_info *);
-extern void sn_more_slot_fixup(struct pci_dev *, struct pcidev_info *);
-extern void sn_legacy_pci_window_fixup(struct pci_controller *, u64, u64);
 extern void sn_io_acpi_init(void);
 extern void sn_io_init(void);
 
@@ -48,6 +44,9 @@ struct sysdata_el {
 
 int sn_ioif_inited;            /* SN I/O infrastructure initialized? */
 
+int sn_acpi_rev;               /* SN ACPI revision */
+EXPORT_SYMBOL_GPL(sn_acpi_rev);
+
 struct sn_pcibus_provider *sn_pci_provider[PCIIO_ASIC_MAX_TYPES];      /* indexed by asic type */
 
 /*
@@ -98,25 +97,6 @@ sal_get_device_dmaflush_list(u64 nasid, u64 widget_num, u64 device_num,
        return ret_stuff.status;
 }
 
-/*
- * Retrieve the pci device information given the bus and device|function number.
- */
-static inline u64
-sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
-                   u64 sn_irq_info)
-{
-       struct ia64_sal_retval ret_stuff;
-       ret_stuff.status = 0;
-       ret_stuff.v0 = 0;
-
-       SAL_CALL_NOLOCK(ret_stuff,
-                       (u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
-                       (u64) segment, (u64) bus_number, (u64) devfn,
-                       (u64) pci_dev,
-                       sn_irq_info, 0, 0);
-       return ret_stuff.v0;
-}
-
 /*
  * sn_pcidev_info_get() - Retrieve the pcidev_info struct for the specified
  *                       device.
@@ -249,50 +229,25 @@ void sn_pci_unfixup_slot(struct pci_dev *dev)
 }
 
 /*
- * sn_pci_fixup_slot() - This routine sets up a slot's resources consistent
- *                      with the Linux PCI abstraction layer. Resources
- *                      acquired from our PCI provider include PIO maps
- *                      to BAR space and interrupt objects.
+ * sn_pci_fixup_slot()
  */
-void sn_pci_fixup_slot(struct pci_dev *dev)
+void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *pcidev_info,
+                      struct sn_irq_info *sn_irq_info)
 {
        int segment = pci_domain_nr(dev->bus);
-       int status = 0;
        struct pcibus_bussoft *bs;
-       struct pci_bus *host_pci_bus;
-       struct pci_dev *host_pci_dev;
-       struct pcidev_info *pcidev_info;
-       struct sn_irq_info *sn_irq_info;
-       unsigned int bus_no, devfn;
+       struct pci_bus *host_pci_bus;
+       struct pci_dev *host_pci_dev;
+       unsigned int bus_no, devfn;
 
        pci_dev_get(dev); /* for the sysdata pointer */
-       pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
-       if (!pcidev_info)
-               BUG();          /* Cannot afford to run out of memory */
-
-       sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
-       if (!sn_irq_info)
-               BUG();          /* Cannot afford to run out of memory */
-
-       /* Call to retrieve pci device information needed by kernel. */
-       status = sal_get_pcidev_info((u64) segment, (u64) dev->bus->number,
-                                    dev->devfn,
-                                    (u64) __pa(pcidev_info),
-                                    (u64) __pa(sn_irq_info));
-       if (status)
-               BUG(); /* Cannot get platform pci device information */
 
        /* Add pcidev_info to list in pci_controller.platform_data */
        list_add_tail(&pcidev_info->pdi_list,
                      &(SN_PLATFORM_DATA(dev->bus)->pcidev_info));
-
-       if (SN_ACPI_BASE_SUPPORT())
-               sn_acpi_slot_fixup(dev, pcidev_info);
-       else
-               sn_more_slot_fixup(dev, pcidev_info);
        /*
         * Using the PROMs values for the PCI host bus, get the Linux
-        * PCI host_pci_dev struct and set up host bus linkages
+        * PCI host_pci_dev struct and set up host bus linkages
         */
 
        bus_no = (pcidev_info->pdi_slot_host_handle >> 32) & 0xff;
@@ -489,11 +444,6 @@ void sn_generate_path(struct pci_bus *pci_bus, char *address)
                        sprintf(address, "%s^%d", address, geo_slot(geoid));
 }
 
-/*
- * sn_pci_fixup_bus() - Perform SN specific setup of software structs
- *                     (pcibus_bussoft, pcidev_info) and hardware
- *                     registers, for the specified bus and devices under it.
- */
 void __devinit
 sn_pci_fixup_bus(struct pci_bus *bus)
 {
@@ -519,6 +469,15 @@ sn_io_early_init(void)
        if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM())
                return 0;
 
+       /* we set the acpi revision to that of the DSDT table OEM rev. */
+       {
+               struct acpi_table_header *header = NULL;
+
+               acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header);
+               BUG_ON(header == NULL);
+               sn_acpi_rev = header->oem_revision;
+       }
+
        /*
         * prime sn_pci_provider[].  Individial provider init routines will
         * override their respective default entries.
@@ -544,8 +503,12 @@ sn_io_early_init(void)
        register_sn_procfs();
 #endif
 
-       printk(KERN_INFO "ACPI  DSDT OEM Rev 0x%x\n",
-              acpi_gbl_DSDT->oem_revision);
+       {
+               struct acpi_table_header *header;
+               (void)acpi_get_table_by_index(ACPI_TABLE_INDEX_DSDT, &header);
+               printk(KERN_INFO "ACPI  DSDT OEM Rev 0x%x\n",
+                       header->oem_revision);
+       }
        if (SN_ACPI_BASE_SUPPORT())
                sn_io_acpi_init();
        else
@@ -605,7 +568,6 @@ sn_io_late_init(void)
 
 fs_initcall(sn_io_late_init);
 
-EXPORT_SYMBOL(sn_pci_fixup_slot);
 EXPORT_SYMBOL(sn_pci_unfixup_slot);
 EXPORT_SYMBOL(sn_bus_store_sysdata);
 EXPORT_SYMBOL(sn_bus_free_sysdata);
index 9ad843e..600be3e 100644 (file)
@@ -56,6 +56,25 @@ static inline u64 sal_get_pcibus_info(u64 segment, u64 busnum, u64 address)
        return ret_stuff.v0;
 }
 
+/*
+ * Retrieve the pci device information given the bus and device|function number.
+ */
+static inline u64
+sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
+                   u64 sn_irq_info)
+{
+       struct ia64_sal_retval ret_stuff;
+       ret_stuff.status = 0;
+       ret_stuff.v0 = 0;
+
+       SAL_CALL_NOLOCK(ret_stuff,
+                       (u64) SN_SAL_IOIF_GET_PCIDEV_INFO,
+                       (u64) segment, (u64) bus_number, (u64) devfn,
+                       (u64) pci_dev,
+                       sn_irq_info, 0, 0);
+       return ret_stuff.v0;
+}
+
 
 /*
  * sn_fixup_ionodes() - This routine initializes the HUB data structure for
@@ -172,18 +191,40 @@ sn_pci_window_fixup(struct pci_dev *dev, unsigned int count,
 }
 
 /*
- * sn_more_slot_fixup() - We are not running with an ACPI capable PROM,
+ * sn_io_slot_fixup() -   We are not running with an ACPI capable PROM,
  *                       and need to convert the pci_dev->resource
  *                       'start' and 'end' addresses to mapped addresses,
  *                       and setup the pci_controller->window array entries.
  */
 void
-sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
+sn_io_slot_fixup(struct pci_dev *dev)
 {
        unsigned int count = 0;
        int idx;
        s64 pci_addrs[PCI_ROM_RESOURCE + 1];
        unsigned long addr, end, size, start;
+       struct pcidev_info *pcidev_info;
+       struct sn_irq_info *sn_irq_info;
+       int status;
+
+       pcidev_info = kzalloc(sizeof(struct pcidev_info), GFP_KERNEL);
+       if (!pcidev_info)
+               panic("%s: Unable to alloc memory for pcidev_info", __FUNCTION__);
+
+       sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
+       if (!sn_irq_info)
+               panic("%s: Unable to alloc memory for sn_irq_info", __FUNCTION__);
+
+       /* Call to retrieve pci device information needed by kernel. */
+       status = sal_get_pcidev_info((u64) pci_domain_nr(dev),
+               (u64) dev->bus->number,
+               dev->devfn,
+               (u64) __pa(pcidev_info),
+               (u64) __pa(sn_irq_info));
+
+       if (status)
+               BUG(); /* Cannot get platform pci device information */
+
 
        /* Copy over PIO Mapped Addresses */
        for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
@@ -219,8 +260,12 @@ sn_more_slot_fixup(struct pci_dev *dev, struct pcidev_info *pcidev_info)
         */
        if (count > 0)
                sn_pci_window_fixup(dev, count, pci_addrs);
+
+       sn_pci_fixup_slot(dev, pcidev_info, sn_irq_info);
 }
 
+EXPORT_SYMBOL(sn_io_slot_fixup);
+
 /*
  * sn_pci_controller_fixup() - This routine sets up a bus's resources
  *                            consistent with the Linux PCI abstraction layer.
@@ -272,9 +317,6 @@ sn_bus_fixup(struct pci_bus *bus)
 {
        struct pci_dev *pci_dev = NULL;
        struct pcibus_bussoft *prom_bussoft_ptr;
-       extern void sn_common_bus_fixup(struct pci_bus *,
-                                       struct pcibus_bussoft *);
-
 
        if (!bus->parent) {  /* If root bus */
                prom_bussoft_ptr = PCI_CONTROLLER(bus)->platform_data;
@@ -291,7 +333,7 @@ sn_bus_fixup(struct pci_bus *bus)
                                           prom_bussoft_ptr->bs_legacy_mem);
         }
         list_for_each_entry(pci_dev, &bus->devices, bus_list) {
-                sn_pci_fixup_slot(pci_dev);
+                sn_io_slot_fixup(pci_dev);
         }
 
 }
index 4aa4f30..ab7e2fd 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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.
  * @port: port to convert
  *
  * Legacy in/out instructions are converted to ld/st instructions
- * on IA64.  This routine will convert a port number into a valid 
+ * on IA64.  This routine will convert a port number into a valid
  * SN i/o address.  Used by sn_in*() and sn_out*().
  */
+
 void *sn_io_addr(unsigned long port)
 {
        if (!IS_RUNNING_ON_SIMULATOR()) {
index b3a435f..ea3dc38 100644 (file)
@@ -59,13 +59,12 @@ void sn_teardown_msi_irq(unsigned int irq)
        sn_intr_free(nasid, widget, sn_irq_info);
        sn_msi_info[irq].sn_irq_info = NULL;
 
-       return;
+       destroy_irq(irq);
 }
 
-int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
+int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry)
 {
        struct msi_msg msg;
-       struct msi_desc *entry;
        int widget;
        int status;
        nasid_t nasid;
@@ -73,8 +72,8 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
        struct sn_irq_info *sn_irq_info;
        struct pcibus_bussoft *bussoft = SN_PCIDEV_BUSSOFT(pdev);
        struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
+       int irq;
 
-       entry = get_irq_data(irq);
        if (!entry->msi_attrib.is_64)
                return -EINVAL;
 
@@ -84,6 +83,11 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
        if (provider == NULL || provider->dma_map_consistent == NULL)
                return -EINVAL;
 
+       irq = create_irq();
+       if (irq < 0)
+               return irq;
+
+       set_irq_msi(irq, entry);
        /*
         * Set up the vector plumbing.  Let the prom (via sn_intr_alloc)
         * decide which cpu to direct this msi at by default.
@@ -95,12 +99,15 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
                        SWIN_WIDGETNUM(bussoft->bs_base);
 
        sn_irq_info = kzalloc(sizeof(struct sn_irq_info), GFP_KERNEL);
-       if (! sn_irq_info)
+       if (! sn_irq_info) {
+               destroy_irq(irq);
                return -ENOMEM;
+       }
 
        status = sn_intr_alloc(nasid, widget, sn_irq_info, irq, -1, -1);
        if (status) {
                kfree(sn_irq_info);
+               destroy_irq(irq);
                return -ENOMEM;
        }
 
@@ -121,6 +128,7 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
        if (! bus_addr) {
                sn_intr_free(nasid, widget, sn_irq_info);
                kfree(sn_irq_info);
+               destroy_irq(irq);
                return -ENOMEM;
        }
 
@@ -139,7 +147,7 @@ int sn_setup_msi_irq(unsigned int irq, struct pci_dev *pdev)
        write_msi_msg(irq, &msg);
        set_irq_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
 
-       return 0;
+       return irq;
 }
 
 #ifdef CONFIG_SMP
index 6846dc9..04a8256 100644 (file)
@@ -20,7 +20,8 @@
 #include "xtalk/hubdev.h"
 
 int
-sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp)
+sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp,
+                      char **ssdt)
 {
        struct ia64_sal_retval ret_stuff;
        u64 busnum;
@@ -32,7 +33,8 @@ sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp)
        segment = soft->pbi_buscommon.bs_persist_segment;
        busnum = soft->pbi_buscommon.bs_persist_busnum;
        SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, segment,
-                       busnum, (u64) device, (u64) resp, 0, 0, 0);
+                       busnum, (u64) device, (u64) resp, (u64)ia64_tpa(ssdt),
+                       0, 0);
 
        return (int)ret_stuff.v0;
 }
index bbd386f..44a0224 100644 (file)
@@ -575,6 +575,7 @@ config SGI_IP27
        select DMA_IP27
        select EARLY_PRINTK
        select HW_HAS_PCI
+       select NR_CPUS_DEFAULT_64
        select PCI_DOMAINS
        select SYS_HAS_CPU_R10000
        select SYS_SUPPORTS_64BIT_KERNEL
@@ -612,6 +613,7 @@ config SIBYTE_BIGSUR
        bool "Sibyte BCM91480B-BigSur"
        select BOOT_ELF32
        select DMA_COHERENT
+       select NR_CPUS_DEFAULT_4
        select PCI_DOMAINS
        select SIBYTE_BCM1x80
        select SWAP_IO_SPACE
@@ -623,6 +625,7 @@ config SIBYTE_SWARM
        bool "Sibyte BCM91250A-SWARM"
        select BOOT_ELF32
        select DMA_COHERENT
+       select NR_CPUS_DEFAULT_2
        select SIBYTE_SB1250
        select SWAP_IO_SPACE
        select SYS_HAS_CPU_SB1
@@ -635,6 +638,7 @@ config SIBYTE_SENTOSA
        depends on EXPERIMENTAL
        select BOOT_ELF32
        select DMA_COHERENT
+       select NR_CPUS_DEFAULT_2
        select SIBYTE_SB1250
        select SWAP_IO_SPACE
        select SYS_HAS_CPU_SB1
@@ -668,6 +672,7 @@ config SIBYTE_PTSWARM
        depends on EXPERIMENTAL
        select BOOT_ELF32
        select DMA_COHERENT
+       select NR_CPUS_DEFAULT_2
        select SIBYTE_SB1250
        select SWAP_IO_SPACE
        select SYS_HAS_CPU_SB1
@@ -680,6 +685,7 @@ config SIBYTE_LITTLESUR
        depends on EXPERIMENTAL
        select BOOT_ELF32
        select DMA_COHERENT
+       select NR_CPUS_DEFAULT_2
        select SIBYTE_SB1250
        select SWAP_IO_SPACE
        select SYS_HAS_CPU_SB1
@@ -790,23 +796,6 @@ config TOSHIBA_RBTX4938
 
 endchoice
 
-config KEXEC
-       bool "Kexec system call (EXPERIMENTAL)"
-       depends on EXPERIMENTAL
-       help
-         kexec is a system call that implements the ability to shutdown your
-         current kernel, and to start another kernel.  It is like a reboot
-         but it is indepedent of the system firmware.   And like a reboot
-         you can start any kernel with it, not just Linux.
-
-         The name comes from the similiarity to the exec system call.
-
-         It is an ongoing process to be certain the hardware in a machine
-         is properly shutdown, so do not be surprised if this code does not
-         initially work for you.  It may help to enable device hotplugging
-         support.  As of this writing the exact hardware interface is
-         strongly in flux, so no good recommendation can be made.
-
 source "arch/mips/ddb5xxx/Kconfig"
 source "arch/mips/gt64120/ev64120/Kconfig"
 source "arch/mips/jazz/Kconfig"
@@ -1541,6 +1530,8 @@ config MIPS_MT_SMTC
        select CPU_MIPSR2_IRQ_VI
        select CPU_MIPSR2_SRS
        select MIPS_MT
+       select NR_CPUS_DEFAULT_2
+       select NR_CPUS_DEFAULT_8
        select SMP
        select SYS_SUPPORTS_SMP
        help
@@ -1756,13 +1747,34 @@ config SMP
 config SYS_SUPPORTS_SMP
        bool
 
+config NR_CPUS_DEFAULT_2
+       bool
+
+config NR_CPUS_DEFAULT_4
+       bool
+
+config NR_CPUS_DEFAULT_8
+       bool
+
+config NR_CPUS_DEFAULT_16
+       bool
+
+config NR_CPUS_DEFAULT_32
+       bool
+
+config NR_CPUS_DEFAULT_64
+       bool
+
 config NR_CPUS
        int "Maximum number of CPUs (2-64)"
        range 2 64
        depends on SMP
-       default "64" if SGI_IP27
-       default "2"
-       default "8" if MIPS_MT_SMTC
+       default "2" if NR_CPUS_DEFAULT_2
+       default "4" if NR_CPUS_DEFAULT_4
+       default "8" if NR_CPUS_DEFAULT_8
+       default "16" if NR_CPUS_DEFAULT_16
+       default "32" if NR_CPUS_DEFAULT_32
+       default "64" if NR_CPUS_DEFAULT_64
        help
          This allows you to specify the maximum number of CPUs which this
          kernel will support.  The maximum supported value is 32 for 32-bit
@@ -1859,6 +1871,40 @@ config MIPS_INSANE_LARGE
          This will result in additional memory usage, so it is not
          recommended for normal users.
 
+config KEXEC
+       bool "Kexec system call (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       help
+         kexec is a system call that implements the ability to shutdown your
+         current kernel, and to start another kernel.  It is like a reboot
+         but it is indepedent of the system firmware.   And like a reboot
+         you can start any kernel with it, not just Linux.
+
+         The name comes from the similiarity to the exec system call.
+
+         It is an ongoing process to be certain the hardware in a machine
+         is properly shutdown, so do not be surprised if this code does not
+         initially work for you.  It may help to enable device hotplugging
+         support.  As of this writing the exact hardware interface is
+         strongly in flux, so no good recommendation can be made.
+
+config SECCOMP
+       bool "Enable seccomp to safely compute untrusted bytecode"
+       depends on PROC_FS && BROKEN
+       default y
+       help
+         This kernel feature is useful for number crunching applications
+         that may need to compute untrusted bytecode during their
+         execution. By using pipes or other transports made available to
+         the process as file descriptors supporting the read/write
+         syscalls, it's possible to isolate those applications in
+         their own address space using seccomp. Once seccomp is
+         enabled via /proc/<pid>/seccomp, it cannot be disabled
+         and the task is only allowed to execute a few safe syscalls
+         defined by each seccomp mode.
+
+         If unsure, say Y. Only embedded should say N here.
+
 endmenu
 
 config RWSEM_GENERIC_SPINLOCK
@@ -2025,23 +2071,6 @@ config BINFMT_ELF32
        bool
        default y if MIPS32_O32 || MIPS32_N32
 
-config SECCOMP
-       bool "Enable seccomp to safely compute untrusted bytecode"
-       depends on PROC_FS && BROKEN
-       default y
-       help
-         This kernel feature is useful for number crunching applications
-         that may need to compute untrusted bytecode during their
-         execution. By using pipes or other transports made available to
-         the process as file descriptors supporting the read/write
-         syscalls, it's possible to isolate those applications in
-         their own address space using seccomp. Once seccomp is
-         enabled via /proc/<pid>/seccomp, it cannot be disabled
-         and the task is only allowed to execute a few safe syscalls
-         defined by each seccomp mode.
-
-         If unsure, say Y. Only embedded should say N here.
-
 config PM
        bool "Power Management support (EXPERIMENTAL)"
        depends on EXPERIMENTAL && SOC_AU1X00
index 5d6afb5..9351f1c 100644 (file)
@@ -22,10 +22,10 @@ config CMDLINE
        string "Default kernel command string"
        default ""
        help
-          On some platforms, there is currently no way for the boot loader to
-          pass arguments to the kernel. For these platforms, you can supply
-          some command-line options at build time by entering them here.  In
-          other cases you can specify kernel args so that you don't have
+         On some platforms, there is currently no way for the boot loader to
+         pass arguments to the kernel. For these platforms, you can supply
+         some command-line options at build time by entering them here.  In
+         other cases you can specify kernel args so that you don't have
          to set them up in board prom initialization routines.
 
 config DEBUG_STACK_USAGE
index 3ba7c47..4b90736 100644 (file)
@@ -77,7 +77,7 @@ static struct smatch * __init string_to_mach(const char *s)
 {
        int i;
 
-       for (i = 0; i < (sizeof(mach_table) / sizeof (mach_table[0])); i++) {
+       for (i = 0; i < ARRAY_SIZE(mach_table); i++) {
                if (!strcmp(s, mach_table[i].arcname))
                        return &mach_table[i];
        }
index 8a9ef58..456cb81 100644 (file)
@@ -141,30 +141,20 @@ void __init prom_meminit(void)
        }
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       unsigned long freed = 0;
        unsigned long addr;
        int i;
 
        if (prom_flags & PROM_FLAG_DONT_FREE_TEMP)
-               return 0;
+               return;
 
        for (i = 0; i < boot_mem_map.nr_map; i++) {
                if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
                        continue;
 
                addr = boot_mem_map.map[i].addr;
-               while (addr < boot_mem_map.map[i].addr
-                             + boot_mem_map.map[i].size) {
-                       ClearPageReserved(virt_to_page(__va(addr)));
-                       init_page_count(virt_to_page(__va(addr)));
-                       free_page((unsigned long)__va(addr));
-                       addr += PAGE_SIZE;
-                       freed += PAGE_SIZE;
-               }
+               free_init_pages("prom memory",
+                               addr, addr + boot_mem_map.map[i].size);
        }
-       printk(KERN_INFO "Freeing prom memory: %ldkb freed\n", freed >> 10);
-
-       return freed;
 }
index 9cf7b67..ea6e99f 100644 (file)
@@ -233,7 +233,7 @@ void restore_local_and_enable(int controller, unsigned long mask)
 
 
 static struct irq_chip rise_edge_irq_type = {
-       .typename = "Au1000 Rise Edge",
+       .name = "Au1000 Rise Edge",
        .ack = mask_and_ack_rise_edge_irq,
        .mask = local_disable_irq,
        .mask_ack = mask_and_ack_rise_edge_irq,
@@ -242,7 +242,7 @@ static struct irq_chip rise_edge_irq_type = {
 };
 
 static struct irq_chip fall_edge_irq_type = {
-       .typename = "Au1000 Fall Edge",
+       .name = "Au1000 Fall Edge",
        .ack = mask_and_ack_fall_edge_irq,
        .mask = local_disable_irq,
        .mask_ack = mask_and_ack_fall_edge_irq,
@@ -251,7 +251,7 @@ static struct irq_chip fall_edge_irq_type = {
 };
 
 static struct irq_chip either_edge_irq_type = {
-       .typename = "Au1000 Rise or Fall Edge",
+       .name = "Au1000 Rise or Fall Edge",
        .ack = mask_and_ack_either_edge_irq,
        .mask = local_disable_irq,
        .mask_ack = mask_and_ack_either_edge_irq,
@@ -260,7 +260,7 @@ static struct irq_chip either_edge_irq_type = {
 };
 
 static struct irq_chip level_irq_type = {
-       .typename = "Au1000 Level",
+       .name = "Au1000 Level",
        .ack = mask_and_ack_level_irq,
        .mask = local_disable_irq,
        .mask_ack = mask_and_ack_level_irq,
index 9f8ce08..6c25e6c 100644 (file)
@@ -76,13 +76,17 @@ static int __init au1x_pci_setup(void)
        }
 
 #ifdef CONFIG_DMA_NONCOHERENT
-       /*
-         *  Set the NC bit in controller for Au1500 pre-AC silicon
-        */
-       u32 prid = read_c0_prid();
-       if ( (prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) {
-              au_writel( 1<<16 | au_readl(Au1500_PCI_CFG), Au1500_PCI_CFG);
-              printk("Non-coherent PCI accesses enabled\n");
+       {
+               /*
+                *  Set the NC bit in controller for Au1500 pre-AC silicon
+                */
+               u32 prid = read_c0_prid();
+
+               if ((prid & 0xFF000000) == 0x01000000 && prid < 0x01030202) {
+                      au_writel((1 << 16) | au_readl(Au1500_PCI_CFG),
+                                Au1500_PCI_CFG);
+                      printk("Non-coherent PCI accesses enabled\n");
+               }
        }
 #endif
 
index 6fce60a..a8637cd 100644 (file)
@@ -149,9 +149,8 @@ int get_ethernet_addr(char *ethernet_addr)
        return 0;
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
 
 EXPORT_SYMBOL(prom_getcmdline);
index 919172d..13fe187 100644 (file)
@@ -141,17 +141,20 @@ void __init plat_mem_setup(void)
 /* This routine should be valid for all Au1x based boards */
 phys_t __fixup_bigphys_addr(phys_t phys_addr, phys_t size)
 {
-       u32 start, end;
-
        /* Don't fixup 36 bit addresses */
-       if ((phys_addr >> 32) != 0) return phys_addr;
+       if ((phys_addr >> 32) != 0)
+               return phys_addr;
 
 #ifdef CONFIG_PCI
-       start = (u32)Au1500_PCI_MEM_START;
-       end = (u32)Au1500_PCI_MEM_END;
-       /* check for pci memory window */
-       if ((phys_addr >= start) && ((phys_addr + size) < end)) {
-               return (phys_t)((phys_addr - start) + Au1500_PCI_MEM_START);
+       {
+               u32 start, end;
+
+               start = (u32)Au1500_PCI_MEM_START;
+               end = (u32)Au1500_PCI_MEM_END;
+               /* check for pci memory window */
+               if ((phys_addr >= start) && ((phys_addr + size) < end))
+                       return (phys_t)
+                              ((phys_addr - start) + Au1500_PCI_MEM_START);
        }
 #endif
 
index 2d1533f..6bc1f8e 100644 (file)
@@ -47,8 +47,7 @@ void board_reset (void)
 
 void __init board_setup(void)
 {
-       u32 pin_func;
-       u32 sys_freqctrl, sys_clksrc;
+       volatile void __iomem * base = (volatile void __iomem *) 0xac000000UL;
 
        // set AUX clock to 12MHz * 8 = 96 MHz
        au_writel(8, SYS_AUXPLL);
@@ -56,58 +55,62 @@ void __init board_setup(void)
        udelay(100);
 
 #ifdef CONFIG_USB_OHCI
-       // configure pins GPIO[14:9] as GPIO
-       pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80);
-
-       /* zero and disable FREQ2 */
-       sys_freqctrl = au_readl(SYS_FREQCTRL0);
-       sys_freqctrl &= ~0xFFF00000;
-       au_writel(sys_freqctrl, SYS_FREQCTRL0);
-
-       /* zero and disable USBH/USBD/IrDA clock */
-       sys_clksrc = au_readl(SYS_CLKSRC);
-       sys_clksrc &= ~0x0000001F;
-       au_writel(sys_clksrc, SYS_CLKSRC);
-
-       sys_freqctrl = au_readl(SYS_FREQCTRL0);
-       sys_freqctrl &= ~0xFFF00000;
-
-       sys_clksrc = au_readl(SYS_CLKSRC);
-       sys_clksrc &= ~0x0000001F;
-
-       // FREQ2 = aux/2 = 48 MHz
-       sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20));
-       au_writel(sys_freqctrl, SYS_FREQCTRL0);
-
-       /*
-        * Route 48MHz FREQ2 into USBH/USBD/IrDA
-        */
-       sys_clksrc |= ((4<<2) | (0<<1) | 0 );
-       au_writel(sys_clksrc, SYS_CLKSRC);
-
-       /* setup the static bus controller */
-       au_writel(0x00000002, MEM_STCFG3);  /* type = PCMCIA */
-       au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */
-       au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */
-
-       // get USB Functionality pin state (device vs host drive pins)
-       pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
-       // 2nd USB port is USB host
-       pin_func |= 0x8000;
-       au_writel(pin_func, SYS_PINFUNC);
+       {
+               u32 pin_func, sys_freqctrl, sys_clksrc;
+
+               // configure pins GPIO[14:9] as GPIO
+               pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x80);
+
+               /* zero and disable FREQ2 */
+               sys_freqctrl = au_readl(SYS_FREQCTRL0);
+               sys_freqctrl &= ~0xFFF00000;
+               au_writel(sys_freqctrl, SYS_FREQCTRL0);
+
+               /* zero and disable USBH/USBD/IrDA clock */
+               sys_clksrc = au_readl(SYS_CLKSRC);
+               sys_clksrc &= ~0x0000001F;
+               au_writel(sys_clksrc, SYS_CLKSRC);
+
+               sys_freqctrl = au_readl(SYS_FREQCTRL0);
+               sys_freqctrl &= ~0xFFF00000;
+
+               sys_clksrc = au_readl(SYS_CLKSRC);
+               sys_clksrc &= ~0x0000001F;
+
+               // FREQ2 = aux/2 = 48 MHz
+               sys_freqctrl |= ((0<<22) | (1<<21) | (1<<20));
+               au_writel(sys_freqctrl, SYS_FREQCTRL0);
+
+               /*
+                * Route 48MHz FREQ2 into USBH/USBD/IrDA
+                */
+               sys_clksrc |= ((4<<2) | (0<<1) | 0 );
+               au_writel(sys_clksrc, SYS_CLKSRC);
+
+               /* setup the static bus controller */
+               au_writel(0x00000002, MEM_STCFG3);  /* type = PCMCIA */
+               au_writel(0x280E3D07, MEM_STTIME3); /* 250ns cycle time */
+               au_writel(0x10000000, MEM_STADDR3); /* any PCMCIA select */
+
+               // get USB Functionality pin state (device vs host drive pins)
+               pin_func = au_readl(SYS_PINFUNC) & (u32)(~0x8000);
+               // 2nd USB port is USB host
+               pin_func |= 0x8000;
+               au_writel(pin_func, SYS_PINFUNC);
+       }
 #endif // defined (CONFIG_USB_OHCI)
 
        /* Enable sys bus clock divider when IDLE state or no bus activity. */
        au_writel(au_readl(SYS_POWERCTRL) | (0x3 << 5), SYS_POWERCTRL);
 
        // Enable the RTC if not already enabled
-       if (!(readb(0xac000028) & 0x20)) {
-               writeb(readb(0xac000028) | 0x20, 0xac000028);
+       if (!(readb(base + 0x28) & 0x20)) {
+               writeb(readb(base + 0x28) | 0x20, base + 0x28);
                au_sync();
        }
        // Put the clock in BCD mode
-       if (readb(0xac00002C) & 0x4) { /* reg B */
-               writeb(readb(0xac00002c) & ~0x4, 0xac00002c);
+       if (readb(base + 0x2C) & 0x4) { /* reg B */
+               writeb(readb(base + 0x2c) & ~0x4, base + 0x2c);
                au_sync();
        }
 }
index 91983ba..b73b2d1 100644 (file)
@@ -137,33 +137,20 @@ static void pb1200_shutdown_irq( unsigned int irq_nr )
        return;
 }
 
-static inline void pb1200_mask_and_ack_irq(unsigned int irq_nr)
-{
-       pb1200_disable_irq( irq_nr );
-}
-
-static void pb1200_end_irq(unsigned int irq_nr)
-{
-       if (!(irq_desc[irq_nr].status & (IRQ_DISABLED|IRQ_INPROGRESS))) {
-               pb1200_enable_irq(irq_nr);
-       }
-}
-
 static struct irq_chip external_irq_type =
 {
 #ifdef CONFIG_MIPS_PB1200
-       "Pb1200 Ext",
+       .name = "Pb1200 Ext",
 #endif
 #ifdef CONFIG_MIPS_DB1200
-       "Db1200 Ext",
+       .name = "Db1200 Ext",
 #endif
-       pb1200_startup_irq,
-       pb1200_shutdown_irq,
-       pb1200_enable_irq,
-       pb1200_disable_irq,
-       pb1200_mask_and_ack_irq,
-       pb1200_end_irq,
-       NULL
+       .startup  = pb1200_startup_irq,
+       .shutdown = pb1200_shutdown_irq,
+       .ack      = pb1200_disable_irq,
+       .mask     = pb1200_disable_irq,
+       .mask_ack = pb1200_disable_irq,
+       .unmask   = pb1200_enable_irq,
 };
 
 void _board_init_irq(void)
@@ -172,7 +159,8 @@ void _board_init_irq(void)
 
        for (irq_nr = PB1200_INT_BEGIN; irq_nr <= PB1200_INT_END; irq_nr++)
        {
-               irq_desc[irq_nr].chip = &external_irq_type;
+               set_irq_chip_and_handler(irq_nr, &external_irq_type,
+                                        handle_level_irq);
                pb1200_disable_irq(irq_nr);
        }
 
index 2e2061a..1ecab63 100644 (file)
@@ -47,9 +47,9 @@ extern asmlinkage void excite_handle_int(void);
  */
 void __init arch_init_irq(void)
 {
-       mips_cpu_irq_init(0);
-       rm7k_cpu_irq_init(8);
-       rm9k_cpu_irq_init(12);
+       mips_cpu_irq_init();
+       rm7k_cpu_irq_init();
+       rm9k_cpu_irq_init();
 
 #ifdef CONFIG_KGDB
        excite_kgdb_init();
index 4c46f0e..fe93b84 100644 (file)
@@ -104,7 +104,7 @@ void __init arch_init_irq(void)
        GT_WRITE(GT_INTRMASK_OFS, 0);
 
        init_i8259_irqs();                              /*  0 ... 15 */
-       mips_cpu_irq_init(COBALT_CPU_IRQ);              /* 16 ... 23 */
+       mips_cpu_irq_init();            /* 16 ... 23 */
 
        /*
         * Mask all cpu interrupts
index e8f0f20..a4b69b5 100644 (file)
@@ -204,8 +204,7 @@ void __init prom_init(void)
        add_memory_region(0x0, memsz, BOOT_MEM_RAM);
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
        /* Nothing to do! */
-       return 0;
 }
index efef0f5..54a857b 100644 (file)
@@ -59,9 +59,8 @@ void __init prom_init(void)
 #endif
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
 
 #if defined(CONFIG_DDB5477)
index a8bd2e6..2b23234 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/ptrace.h>
 
 #include <asm/i8259.h>
+#include <asm/irq_cpu.h>
 #include <asm/system.h>
 #include <asm/mipsregs.h>
 #include <asm/debug.h>
@@ -73,7 +74,6 @@ set_pci_int_attr(u32 pci, u32 intn, u32 active, u32 trigger)
 }
 
 extern void vrc5477_irq_init(u32 base);
-extern void mips_cpu_irq_init(u32 base);
 static struct irqaction irq_cascade = { no_action, 0, CPU_MASK_NONE, "cascade", NULL, NULL };
 
 void __init arch_init_irq(void)
@@ -125,7 +125,7 @@ void __init arch_init_irq(void)
 
        /* init all controllers */
        init_i8259_irqs();
-       mips_cpu_irq_init(CPU_IRQ_BASE);
+       mips_cpu_irq_init();
        vrc5477_irq_init(VRC5477_IRQ_BASE);
 
 
@@ -146,8 +146,7 @@ u8 i8259_interrupt_ack(void)
        irq = *(volatile u8 *) KSEG1ADDR(DDB_PCI_IACK_BASE);
        ddb_out32(DDB_PCIINIT10, reg);
 
-       /* i8259.c set the base vector to be 0x0 */
-       return irq + I8259_IRQ_BASE;
+       return irq;
 }
 /*
  * the first level int-handler will jump here if it is a vrc5477 irq
@@ -177,7 +176,7 @@ static void vrc5477_irq_dispatch(void)
                /* check for i8259 interrupts */
                if (intStatus & (1 << VRC5477_I8259_CASCADE)) {
                        int i8259_irq = i8259_interrupt_ack();
-                       do_IRQ(I8259_IRQ_BASE + i8259_irq);
+                       do_IRQ(i8259_irq);
                        return;
                }
        }
index 96249aa..98c3b15 100644 (file)
@@ -82,7 +82,7 @@ vrc5477_irq_end(unsigned int irq)
 }
 
 struct irq_chip vrc5477_irq_controller = {
-       .typename = "vrc5477_irq",
+       .name = "vrc5477_irq",
        .ack = vrc5477_irq_ack,
        .mask = vrc5477_irq_disable,
        .mask_ack = vrc5477_irq_ack,
index 4c7cb40..3acb133 100644 (file)
@@ -62,7 +62,7 @@ static inline void end_ioasic_irq(unsigned int irq)
 }
 
 static struct irq_chip ioasic_irq_type = {
-       .typename = "IO-ASIC",
+       .name = "IO-ASIC",
        .ack = ack_ioasic_irq,
        .mask = mask_ioasic_irq,
        .mask_ack = ack_ioasic_irq,
@@ -84,7 +84,7 @@ static inline void end_ioasic_dma_irq(unsigned int irq)
 }
 
 static struct irq_chip ioasic_dma_irq_type = {
-       .typename = "IO-ASIC-DMA",
+       .name = "IO-ASIC-DMA",
        .ack = ack_ioasic_dma_irq,
        .mask = mask_ioasic_dma_irq,
        .mask_ack = ack_ioasic_dma_irq,
index 916e46b..02439dc 100644 (file)
@@ -58,7 +58,7 @@ static void ack_kn02_irq(unsigned int irq)
 }
 
 static struct irq_chip kn02_irq_type = {
-       .typename = "KN02-CSR",
+       .name = "KN02-CSR",
        .ack = ack_kn02_irq,
        .mask = mask_kn02_irq,
        .mask_ack = ack_kn02_irq,
index 3aa01d2..5a557e2 100644 (file)
@@ -92,9 +92,9 @@ void __init prom_meminit(u32 magic)
                rex_setup_memory_region();
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       unsigned long addr, end;
+       unsigned long end;
 
        /*
         * Free everything below the kernel itself but leave
@@ -114,16 +114,5 @@ unsigned long __init prom_free_prom_memory(void)
 #endif
                end = __pa(&_text);
 
-       addr = PAGE_SIZE;
-       while (addr < end) {
-               ClearPageReserved(virt_to_page(__va(addr)));
-               init_page_count(virt_to_page(__va(addr)));
-               free_page((unsigned long)__va(addr));
-               addr += PAGE_SIZE;
-       }
-
-       printk("Freeing unused PROM memory: %ldkb freed\n",
-              (end - PAGE_SIZE) >> 10);
-
-       return end - PAGE_SIZE;
+       free_init_pages("unused PROM memory", PAGE_SIZE, end);
 }
index d34032a..1058e2f 100644 (file)
@@ -234,7 +234,7 @@ static void __init dec_init_kn01(void)
        memcpy(&cpu_mask_nr_tbl, &kn01_cpu_mask_nr_tbl,
                sizeof(kn01_cpu_mask_nr_tbl));
 
-       mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+       mips_cpu_irq_init();
 
 }                              /* dec_init_kn01 */
 
@@ -309,7 +309,7 @@ static void __init dec_init_kn230(void)
        memcpy(&cpu_mask_nr_tbl, &kn230_cpu_mask_nr_tbl,
                sizeof(kn230_cpu_mask_nr_tbl));
 
-       mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+       mips_cpu_irq_init();
 
 }                              /* dec_init_kn230 */
 
@@ -403,7 +403,7 @@ static void __init dec_init_kn02(void)
        memcpy(&asic_mask_nr_tbl, &kn02_asic_mask_nr_tbl,
                sizeof(kn02_asic_mask_nr_tbl));
 
-       mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+       mips_cpu_irq_init();
        init_kn02_irqs(KN02_IRQ_BASE);
 
 }                              /* dec_init_kn02 */
@@ -504,7 +504,7 @@ static void __init dec_init_kn02ba(void)
        memcpy(&asic_mask_nr_tbl, &kn02ba_asic_mask_nr_tbl,
                sizeof(kn02ba_asic_mask_nr_tbl));
 
-       mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+       mips_cpu_irq_init();
        init_ioasic_irqs(IO_IRQ_BASE);
 
 }                              /* dec_init_kn02ba */
@@ -601,7 +601,7 @@ static void __init dec_init_kn02ca(void)
        memcpy(&asic_mask_nr_tbl, &kn02ca_asic_mask_nr_tbl,
                sizeof(kn02ca_asic_mask_nr_tbl));
 
-       mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+       mips_cpu_irq_init();
        init_ioasic_irqs(IO_IRQ_BASE);
 
 }                              /* dec_init_kn02ca */
@@ -702,7 +702,7 @@ static void __init dec_init_kn03(void)
        memcpy(&asic_mask_nr_tbl, &kn03_asic_mask_nr_tbl,
                sizeof(kn03_asic_mask_nr_tbl));
 
-       mips_cpu_irq_init(DEC_CPU_IRQ_BASE);
+       mips_cpu_irq_init();
        init_ioasic_irqs(IO_IRQ_BASE);
 
 }                              /* dec_init_kn03 */
index 8d880f0..96df37b 100644 (file)
@@ -57,7 +57,7 @@ static void emma2rh_irq_disable(unsigned int irq)
 }
 
 struct irq_chip emma2rh_irq_controller = {
-       .typename = "emma2rh_irq",
+       .name = "emma2rh_irq",
        .ack = emma2rh_irq_disable,
        .mask = emma2rh_irq_disable,
        .mask_ack = emma2rh_irq_disable,
index c93369c..3299b6d 100644 (file)
@@ -106,7 +106,7 @@ void __init arch_init_irq(void)
        emma2rh_irq_init(EMMA2RH_IRQ_BASE);
        emma2rh_sw_irq_init(EMMA2RH_SW_IRQ_BASE);
        emma2rh_gpio_irq_init(EMMA2RH_GPIO_IRQ_BASE);
-       mips_cpu_irq_init(CPU_IRQ_BASE);
+       mips_cpu_irq_init();
 
        /* setup cascade interrupts */
        setup_irq(EMMA2RH_IRQ_BASE + EMMA2RH_SW_CASCADE, &irq_cascade);
index 2116d9b..fba5c15 100644 (file)
@@ -49,7 +49,7 @@ static void emma2rh_sw_irq_disable(unsigned int irq)
 }
 
 struct irq_chip emma2rh_sw_irq_controller = {
-       .typename = "emma2rh_sw_irq",
+       .name = "emma2rh_sw_irq",
        .ack = emma2rh_sw_irq_disable,
        .mask = emma2rh_sw_irq_disable,
        .mask_ack = emma2rh_sw_irq_disable,
@@ -115,7 +115,7 @@ static void emma2rh_gpio_irq_end(unsigned int irq)
 }
 
 struct irq_chip emma2rh_gpio_irq_controller = {
-       .typename = "emma2rh_gpio_irq",
+       .name = "emma2rh_gpio_irq",
        .ack = emma2rh_gpio_irq_ack,
        .mask = emma2rh_gpio_irq_disable,
        .mask_ack = emma2rh_gpio_irq_ack,
index b3e5796..04572b9 100644 (file)
@@ -88,7 +88,7 @@ static void end_ev64120_irq(unsigned int irq)
 }
 
 static struct irq_chip ev64120_irq_type = {
-       .typename       = "EV64120",
+       .name           = "EV64120",
        .ack            = disable_ev64120_irq,
        .mask           = disable_ev64120_irq,
        .mask_ack       = disable_ev64120_irq,
index 99c8d42..477848c 100644 (file)
@@ -59,9 +59,8 @@ extern void galileo_machine_power_off(void);
  */
 extern struct pci_ops galileo_pci_ops;
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
 
 /*
index 2128684..32d6fb4 100644 (file)
@@ -1,6 +1,4 @@
 
-#ifdef CONFIG_KGDB
-
 #include <asm/serial.h> /* For the serial port location and base baud */
 
 /* --- CONFIG --- */
@@ -121,5 +119,3 @@ int putDebugChar(uint8 byte)
        UART16550_WRITE(OFS_SEND_BUFFER, byte);
        return 1;
 }
-
-#endif
index d929440..2585d9d 100644 (file)
@@ -90,6 +90,6 @@ void __init arch_init_irq(void)
        clear_c0_status(ST0_IM);
        local_irq_disable();
 
-       mips_cpu_irq_init(0);
-       rm7k_cpu_irq_init(8);
+       mips_cpu_irq_init();
+       rm7k_cpu_irq_init();
 }
index 8677b6d..78f393b 100644 (file)
@@ -67,7 +67,6 @@ void __init prom_init(void)
        add_memory_region(0, 64 << 20, BOOT_MEM_RAM);
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
index eedfc24..d3d9659 100644 (file)
@@ -63,7 +63,7 @@ void gt64120_init_pic(void)
 void __init arch_init_irq(void)
 {
        /* IRQ 0 - 7 are for MIPS common irq_cpu controller */
-       mips_cpu_irq_init(0);
+       mips_cpu_irq_init();
 
        gt64120_init_pic();
 }
index 429afc4..121188d 100644 (file)
@@ -93,9 +93,8 @@ void __init wrppmc_early_printk(const char *fmt, ...)
 }
 #endif /* WRPPMC_EARLY_DEBUG */
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
 
 #ifdef CONFIG_SERIAL_8250
index f8d417b..295892e 100644 (file)
@@ -40,7 +40,7 @@ void disable_r4030_irq(unsigned int irq)
 }
 
 static struct irq_chip r4030_irq_type = {
-       .typename = "R4030",
+       .name = "R4030",
        .ack = disable_r4030_irq,
        .mask = disable_r4030_irq,
        .mask_ack = disable_r4030_irq,
index 5d5838f..aa481b7 100644 (file)
@@ -75,7 +75,6 @@ void  __init prom_init_cmdline(void)
        *cp = '\0';
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
index 3da49c5..7d2c203 100644 (file)
@@ -439,7 +439,7 @@ void __init arch_init_irq(void)
 }
 
 static struct irq_chip jmr3927_irq_controller = {
-       .typename = "jmr3927_irq",
+       .name = "jmr3927_irq",
        .ack = jmr3927_irq_ack,
        .mask = jmr3927_irq_disable,
        .mask_ack = jmr3927_irq_ack,
index 138f25e..7ca3d6d 100644 (file)
@@ -434,7 +434,7 @@ void __init tx3927_setup(void)
 
        /* DMA */
        tx3927_dmaptr->mcr = 0;
-       for (i = 0; i < sizeof(tx3927_dmaptr->ch) / sizeof(tx3927_dmaptr->ch[0]); i++) {
+       for (i = 0; i < ARRAY_SIZE(tx3927_dmaptr->ch); i++) {
                /* reset channel */
                tx3927_dmaptr->ch[i].ccr = TX3927_DMA_CCR_CHRST;
                tx3927_dmaptr->ch[i].ccr = 0;
index ff88b06..ea7df4b 100644 (file)
@@ -234,10 +234,6 @@ void output_mm_defines(void)
        constant("#define _PMD_SHIFT     ", PMD_SHIFT);
        constant("#define _PGDIR_SHIFT   ", PGDIR_SHIFT);
        linefeed;
-       constant("#define _PGD_ORDER     ", PGD_ORDER);
-       constant("#define _PMD_ORDER     ", PMD_ORDER);
-       constant("#define _PTE_ORDER     ", PTE_ORDER);
-       linefeed;
        constant("#define _PTRS_PER_PGD  ", PTRS_PER_PGD);
        constant("#define _PTRS_PER_PMD  ", PTRS_PER_PMD);
        constant("#define _PTRS_PER_PTE  ", PTRS_PER_PTE);
index 442839e..f59ef27 100644 (file)
@@ -565,7 +565,7 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
        if (config3 & MIPS_CONF3_VEIC)
                c->options |= MIPS_CPU_VEIC;
        if (config3 & MIPS_CONF3_MT)
-                c->ases |= MIPS_ASE_MIPSMT;
+               c->ases |= MIPS_ASE_MIPSMT;
 
        return config3 & MIPS_CONF_M;
 }
index 719d269..7bc8820 100644 (file)
@@ -505,13 +505,13 @@ void show_gdbregs(struct gdb_regs * regs)
         */
        printk("$0 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
               regs->reg0, regs->reg1, regs->reg2, regs->reg3,
-               regs->reg4, regs->reg5, regs->reg6, regs->reg7);
+              regs->reg4, regs->reg5, regs->reg6, regs->reg7);
        printk("$8 : %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
               regs->reg8, regs->reg9, regs->reg10, regs->reg11,
-               regs->reg12, regs->reg13, regs->reg14, regs->reg15);
+              regs->reg12, regs->reg13, regs->reg14, regs->reg15);
        printk("$16: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
               regs->reg16, regs->reg17, regs->reg18, regs->reg19,
-               regs->reg20, regs->reg21, regs->reg22, regs->reg23);
+              regs->reg20, regs->reg21, regs->reg22, regs->reg23);
        printk("$24: %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
               regs->reg24, regs->reg25, regs->reg26, regs->reg27,
               regs->reg28, regs->reg29, regs->reg30, regs->reg31);
index 9a7811d..6f57ca4 100644 (file)
@@ -231,28 +231,3 @@ NESTED(smp_bootstrap, 16, sp)
 #endif /* CONFIG_SMP */
 
        __FINIT
-
-       .comm   kernelsp,    NR_CPUS * 8, 8
-       .comm   pgd_current, NR_CPUS * 8, 8
-
-       .comm   fw_arg0, SZREG, SZREG           # firmware arguments
-       .comm   fw_arg1, SZREG, SZREG
-       .comm   fw_arg2, SZREG, SZREG
-       .comm   fw_arg3, SZREG, SZREG
-
-       .macro page name, order
-       .comm   \name, (_PAGE_SIZE << \order), (_PAGE_SIZE << \order)
-       .endm
-
-       /*
-        * On 64-bit we've got three-level pagetables with a slightly
-        * different layout ...
-        */
-       page    swapper_pg_dir, _PGD_ORDER
-#ifdef CONFIG_64BIT
-#if defined(CONFIG_MODULES) && !defined(CONFIG_BUILD_ELF64)
-       page    module_pg_dir, _PGD_ORDER
-#endif
-       page    invalid_pmd_table, _PMD_ORDER
-#endif
-       page    invalid_pte_table, _PTE_ORDER
index b59a676..b33ba6c 100644 (file)
@@ -54,9 +54,11 @@ static unsigned int cached_irq_mask = 0xffff;
 
 void disable_8259A_irq(unsigned int irq)
 {
-       unsigned int mask = 1 << irq;
+       unsigned int mask;
        unsigned long flags;
 
+       irq -= I8259A_IRQ_BASE;
+       mask = 1 << irq;
        spin_lock_irqsave(&i8259A_lock, flags);
        cached_irq_mask |= mask;
        if (irq & 8)
@@ -68,9 +70,11 @@ void disable_8259A_irq(unsigned int irq)
 
 void enable_8259A_irq(unsigned int irq)
 {
-       unsigned int mask = ~(1 << irq);
+       unsigned int mask;
        unsigned long flags;
 
+       irq -= I8259A_IRQ_BASE;
+       mask = ~(1 << irq);
        spin_lock_irqsave(&i8259A_lock, flags);
        cached_irq_mask &= mask;
        if (irq & 8)
@@ -82,10 +86,12 @@ void enable_8259A_irq(unsigned int irq)
 
 int i8259A_irq_pending(unsigned int irq)
 {
-       unsigned int mask = 1 << irq;
+       unsigned int mask;
        unsigned long flags;
        int ret;
 
+       irq -= I8259A_IRQ_BASE;
+       mask = 1 << irq;
        spin_lock_irqsave(&i8259A_lock, flags);
        if (irq < 8)
                ret = inb(PIC_MASTER_CMD) & mask;
@@ -134,9 +140,11 @@ static inline int i8259A_irq_real(unsigned int irq)
  */
 void mask_and_ack_8259A(unsigned int irq)
 {
-       unsigned int irqmask = 1 << irq;
+       unsigned int irqmask;
        unsigned long flags;
 
+       irq -= I8259A_IRQ_BASE;
+       irqmask = 1 << irq;
        spin_lock_irqsave(&i8259A_lock, flags);
        /*
         * Lightweight spurious IRQ detection. We do not want
@@ -169,8 +177,8 @@ handle_real_irq:
                outb(0x60+irq,PIC_MASTER_CMD);  /* 'Specific EOI to master */
        }
 #ifdef CONFIG_MIPS_MT_SMTC
-        if (irq_hwmask[irq] & ST0_IM)
-               set_c0_status(irq_hwmask[irq] & ST0_IM);
+       if (irq_hwmask[irq] & ST0_IM)
+               set_c0_status(irq_hwmask[irq] & ST0_IM);
 #endif /* CONFIG_MIPS_MT_SMTC */
        spin_unlock_irqrestore(&i8259A_lock, flags);
        return;
@@ -322,8 +330,8 @@ void __init init_i8259_irqs (void)
 
        init_8259A(0);
 
-       for (i = 0; i < 16; i++)
+       for (i = I8259A_IRQ_BASE; i < I8259A_IRQ_BASE + 16; i++)
                set_irq_chip_and_handler(i, &i8259A_chip, handle_level_irq);
 
-       setup_irq(PIC_CASCADE_IR, &irq2);
+       setup_irq(I8259A_IRQ_BASE + PIC_CASCADE_IR, &irq2);
 }
index 37cad5d..3cc25c0 100644 (file)
@@ -10,6 +10,8 @@
  * Copyright (C) 1996 - 2004 David S. Miller <dm@engr.sgi.com>
  * Copyright (C) 2004 - 2005 Steven J. Hill <sjhill@realitydiluted.com>
  */
+#undef DEBUG
+
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
@@ -40,8 +42,6 @@
 
 #include <linux/elf.h>
 
-#undef DEBUG
-
 static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs);
 static int load_irix_library(struct file *);
 static int irix_core_dump(long signr, struct pt_regs * regs,
@@ -52,72 +52,102 @@ static struct linux_binfmt irix_format = {
        irix_core_dump, PAGE_SIZE
 };
 
-#ifdef DEBUG
 /* Debugging routines. */
 static char *get_elf_p_type(Elf32_Word p_type)
 {
-       int i = (int) p_type;
-
-       switch(i) {
-       case PT_NULL: return("PT_NULL"); break;
-       case PT_LOAD: return("PT_LOAD"); break;
-       case PT_DYNAMIC: return("PT_DYNAMIC"); break;
-       case PT_INTERP: return("PT_INTERP"); break;
-       case PT_NOTE: return("PT_NOTE"); break;
-       case PT_SHLIB: return("PT_SHLIB"); break;
-       case PT_PHDR: return("PT_PHDR"); break;
-       case PT_LOPROC: return("PT_LOPROC/REGINFO"); break;
-       case PT_HIPROC: return("PT_HIPROC"); break;
-       default: return("PT_BOGUS"); break;
+#ifdef DEBUG
+       switch (p_type) {
+       case PT_NULL:
+               return "PT_NULL";
+               break;
+
+       case PT_LOAD:
+               return "PT_LOAD";
+               break;
+
+       case PT_DYNAMIC:
+               return "PT_DYNAMIC";
+               break;
+
+       case PT_INTERP:
+               return "PT_INTERP";
+               break;
+
+       case PT_NOTE:
+               return "PT_NOTE";
+               break;
+
+       case PT_SHLIB:
+               return "PT_SHLIB";
+               break;
+
+       case PT_PHDR:
+               return "PT_PHDR";
+               break;
+
+       case PT_LOPROC:
+               return "PT_LOPROC/REGINFO";
+               break;
+
+       case PT_HIPROC:
+               return "PT_HIPROC";
+               break;
+
+       default:
+               return "PT_BOGUS";
+               break;
        }
+#endif
 }
 
 static void print_elfhdr(struct elfhdr *ehp)
 {
        int i;
 
-       printk("ELFHDR: e_ident<");
-       for(i = 0; i < (EI_NIDENT - 1); i++) printk("%x ", ehp->e_ident[i]);
-       printk("%x>\n", ehp->e_ident[i]);
-       printk("        e_type[%04x] e_machine[%04x] e_version[%08lx]\n",
-              (unsigned short) ehp->e_type, (unsigned short) ehp->e_machine,
-              (unsigned long) ehp->e_version);
-       printk("        e_entry[%08lx] e_phoff[%08lx] e_shoff[%08lx] "
-              "e_flags[%08lx]\n",
-              (unsigned long) ehp->e_entry, (unsigned long) ehp->e_phoff,
-              (unsigned long) ehp->e_shoff, (unsigned long) ehp->e_flags);
-       printk("        e_ehsize[%04x] e_phentsize[%04x] e_phnum[%04x]\n",
-              (unsigned short) ehp->e_ehsize, (unsigned short) ehp->e_phentsize,
-              (unsigned short) ehp->e_phnum);
-       printk("        e_shentsize[%04x] e_shnum[%04x] e_shstrndx[%04x]\n",
-              (unsigned short) ehp->e_shentsize, (unsigned short) ehp->e_shnum,
-              (unsigned short) ehp->e_shstrndx);
+       pr_debug("ELFHDR: e_ident<");
+       for (i = 0; i < (EI_NIDENT - 1); i++)
+               pr_debug("%x ", ehp->e_ident[i]);
+       pr_debug("%x>\n", ehp->e_ident[i]);
+       pr_debug("        e_type[%04x] e_machine[%04x] e_version[%08lx]\n",
+                (unsigned short) ehp->e_type, (unsigned short) ehp->e_machine,
+                (unsigned long) ehp->e_version);
+       pr_debug("        e_entry[%08lx] e_phoff[%08lx] e_shoff[%08lx] "
+                "e_flags[%08lx]\n",
+                (unsigned long) ehp->e_entry, (unsigned long) ehp->e_phoff,
+                (unsigned long) ehp->e_shoff, (unsigned long) ehp->e_flags);
+       pr_debug("        e_ehsize[%04x] e_phentsize[%04x] e_phnum[%04x]\n",
+                (unsigned short) ehp->e_ehsize,
+                (unsigned short) ehp->e_phentsize,
+                (unsigned short) ehp->e_phnum);
+       pr_debug("        e_shentsize[%04x] e_shnum[%04x] e_shstrndx[%04x]\n",
+                (unsigned short) ehp->e_shentsize,
+                (unsigned short) ehp->e_shnum,
+                (unsigned short) ehp->e_shstrndx);
 }
 
 static void print_phdr(int i, struct elf_phdr *ep)
 {
-       printk("PHDR[%d]: p_type[%s] p_offset[%08lx] p_vaddr[%08lx] "
-              "p_paddr[%08lx]\n", i, get_elf_p_type(ep->p_type),
-              (unsigned long) ep->p_offset, (unsigned long) ep->p_vaddr,
-              (unsigned long) ep->p_paddr);
-       printk("         p_filesz[%08lx] p_memsz[%08lx] p_flags[%08lx] "
-              "p_align[%08lx]\n", (unsigned long) ep->p_filesz,
-              (unsigned long) ep->p_memsz, (unsigned long) ep->p_flags,
-              (unsigned long) ep->p_align);
+       pr_debug("PHDR[%d]: p_type[%s] p_offset[%08lx] p_vaddr[%08lx] "
+                "p_paddr[%08lx]\n", i, get_elf_p_type(ep->p_type),
+                (unsigned long) ep->p_offset, (unsigned long) ep->p_vaddr,
+                (unsigned long) ep->p_paddr);
+       pr_debug("         p_filesz[%08lx] p_memsz[%08lx] p_flags[%08lx] "
+                "p_align[%08lx]\n", (unsigned long) ep->p_filesz,
+                (unsigned long) ep->p_memsz, (unsigned long) ep->p_flags,
+                (unsigned long) ep->p_align);
 }
 
 static void dump_phdrs(struct elf_phdr *ep, int pnum)
 {
        int i;
 
-       for(i = 0; i < pnum; i++, ep++) {
-               if((ep->p_type == PT_LOAD) ||
-                  (ep->p_type == PT_INTERP) ||
-                  (ep->p_type == PT_PHDR))
+       for (i = 0; i < pnum; i++, ep++) {
+               if ((ep->p_type == PT_LOAD) ||
+                   (ep->p_type == PT_INTERP) ||
+                   (ep->p_type == PT_PHDR))
                        print_phdr(i, ep);
        }
 }
-#endif /* DEBUG */
 
 static void set_brk(unsigned long start, unsigned long end)
 {
@@ -156,11 +186,10 @@ static unsigned long * create_irix_tables(char * p, int argc, int envc,
        elf_addr_t *envp;
        elf_addr_t *sp, *csp;
 
-#ifdef DEBUG
-       printk("create_irix_tables: p[%p] argc[%d] envc[%d] "
-              "load_addr[%08x] interp_load_addr[%08x]\n",
-              p, argc, envc, load_addr, interp_load_addr);
-#endif
+       pr_debug("create_irix_tables: p[%p] argc[%d] envc[%d] "
+                "load_addr[%08x] interp_load_addr[%08x]\n",
+                p, argc, envc, load_addr, interp_load_addr);
+
        sp = (elf_addr_t *) (~15UL & (unsigned long) p);
        csp = sp;
        csp -= exec ? DLINFO_ITEMS*2 : 2;
@@ -181,7 +210,7 @@ static unsigned long * create_irix_tables(char * p, int argc, int envc,
        sp -= 2;
        NEW_AUX_ENT(0, AT_NULL, 0);
 
-       if(exec) {
+       if (exec) {
                sp -= 11*2;
 
                NEW_AUX_ENT (0, AT_PHDR, load_addr + exec->e_phoff);
@@ -245,9 +274,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
        last_bss = 0;
        error = load_addr = 0;
 
-#ifdef DEBUG
        print_elfhdr(interp_elf_ex);
-#endif
 
        /* First of all, some simple consistency checks */
        if ((interp_elf_ex->e_type != ET_EXEC &&
@@ -258,7 +285,7 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
        }
 
        /* Now read in all of the header information */
-       if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) {
+       if (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE) {
            printk("IRIX interp header bigger than a page (%d)\n",
                   (sizeof(struct elf_phdr) * interp_elf_ex->e_phnum));
            return 0xffffffff;
@@ -267,15 +294,15 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
        elf_phdata = kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum,
                             GFP_KERNEL);
 
-       if(!elf_phdata) {
-          printk("Cannot kmalloc phdata for IRIX interp.\n");
-         return 0xffffffff;
+       if (!elf_phdata) {
+               printk("Cannot kmalloc phdata for IRIX interp.\n");
+               return 0xffffffff;
        }
 
        /* If the size of this structure has changed, then punt, since
         * we will be doing the wrong thing.
         */
-       if(interp_elf_ex->e_phentsize != 32) {
+       if (interp_elf_ex->e_phentsize != 32) {
                printk("IRIX interp e_phentsize == %d != 32 ",
                       interp_elf_ex->e_phentsize);
                kfree(elf_phdata);
@@ -286,61 +313,71 @@ static unsigned int load_irix_interp(struct elfhdr * interp_elf_ex,
                           (char *) elf_phdata,
                           sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
 
-#ifdef DEBUG
        dump_phdrs(elf_phdata, interp_elf_ex->e_phnum);
-#endif
 
        eppnt = elf_phdata;
-       for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++) {
-         if(eppnt->p_type == PT_LOAD) {
-           int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
-           int elf_prot = 0;
-           unsigned long vaddr = 0;
-           if (eppnt->p_flags & PF_R) elf_prot =  PROT_READ;
-           if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE;
-           if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC;
-           elf_type |= MAP_FIXED;
-           vaddr = eppnt->p_vaddr;
-
-           pr_debug("INTERP do_mmap(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ",
-                  interpreter, vaddr,
-                  (unsigned long) (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)),
-                  (unsigned long) elf_prot, (unsigned long) elf_type,
-                  (unsigned long) (eppnt->p_offset & 0xfffff000));
-           down_write(&current->mm->mmap_sem);
-           error = do_mmap(interpreter, vaddr,
-                           eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
-                           elf_prot, elf_type,
-                           eppnt->p_offset & 0xfffff000);
-           up_write(&current->mm->mmap_sem);
-
-           if(error < 0 && error > -1024) {
-                   printk("Aieee IRIX interp mmap error=%d\n", error);
-                   break;  /* Real error */
-           }
-           pr_debug("error=%08lx ", (unsigned long) error);
-           if(!load_addr && interp_elf_ex->e_type == ET_DYN) {
-             load_addr = error;
-              pr_debug("load_addr = error ");
-           }
-
-           /* Find the end of the file  mapping for this phdr, and keep
-            * track of the largest address we see for this.
-            */
-           k = eppnt->p_vaddr + eppnt->p_filesz;
-           if(k > elf_bss) elf_bss = k;
-
-           /* Do the same thing for the memory mapping - between
-            * elf_bss and last_bss is the bss section.
-            */
-           k = eppnt->p_memsz + eppnt->p_vaddr;
-           if(k > last_bss) last_bss = k;
-           pr_debug("\n");
-         }
+       for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) {
+               if (eppnt->p_type == PT_LOAD) {
+                       int elf_type = MAP_PRIVATE | MAP_DENYWRITE;
+                       int elf_prot = 0;
+                       unsigned long vaddr = 0;
+                       if (eppnt->p_flags & PF_R)
+                               elf_prot =  PROT_READ;
+                       if (eppnt->p_flags & PF_W)
+                               elf_prot |= PROT_WRITE;
+                       if (eppnt->p_flags & PF_X)
+                               elf_prot |= PROT_EXEC;
+                       elf_type |= MAP_FIXED;
+                       vaddr = eppnt->p_vaddr;
+
+                       pr_debug("INTERP do_mmap"
+                                "(%p, %08lx, %08lx, %08lx, %08lx, %08lx) ",
+                                interpreter, vaddr,
+                                (unsigned long)
+                                (eppnt->p_filesz + (eppnt->p_vaddr & 0xfff)),
+                                (unsigned long)
+                                elf_prot, (unsigned long) elf_type,
+                                (unsigned long)
+                                (eppnt->p_offset & 0xfffff000));
+
+                       down_write(&current->mm->mmap_sem);
+                       error = do_mmap(interpreter, vaddr,
+                       eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
+                       elf_prot, elf_type,
+                       eppnt->p_offset & 0xfffff000);
+                       up_write(&current->mm->mmap_sem);
+
+                       if (error < 0 && error > -1024) {
+                               printk("Aieee IRIX interp mmap error=%d\n",
+                                      error);
+                               break;  /* Real error */
+                       }
+                       pr_debug("error=%08lx ", (unsigned long) error);
+                       if (!load_addr && interp_elf_ex->e_type == ET_DYN) {
+                               load_addr = error;
+                               pr_debug("load_addr = error ");
+                       }
+
+                       /*
+                        * Find the end of the file  mapping for this phdr, and
+                        * keep track of the largest address we see for this.
+                        */
+                       k = eppnt->p_vaddr + eppnt->p_filesz;
+                       if (k > elf_bss)
+                               elf_bss = k;
+
+                       /* Do the same thing for the memory mapping - between
+                        * elf_bss and last_bss is the bss section.
+                        */
+                       k = eppnt->p_memsz + eppnt->p_vaddr;
+                       if (k > last_bss)
+                               last_bss = k;
+                       pr_debug("\n");
+               }
        }
 
        /* Now use mmap to map the library into memory. */
-       if(error < 0 && error > -1024) {
+       if (error < 0 && error > -1024) {
                pr_debug("got error %d\n", error);
                kfree(elf_phdata);
                return 0xffffffff;
@@ -377,7 +414,7 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm)
                return -ENOEXEC;
 
        /* First of all, some simple consistency checks */
-       if((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) ||
+       if ((ehp->e_type != ET_EXEC && ehp->e_type != ET_DYN) ||
            !bprm->file->f_op->mmap) {
                return -ENOEXEC;
        }
@@ -388,7 +425,7 @@ static int verify_binary(struct elfhdr *ehp, struct linux_binprm *bprm)
         * XXX all registers as 64bits on cpu's capable of this at
         * XXX exception time plus frob the XTLB exception vector.
         */
-       if((ehp->e_flags & EF_MIPS_ABI2))
+       if ((ehp->e_flags & EF_MIPS_ABI2))
                return -ENOEXEC;
 
        return 0;
@@ -410,7 +447,7 @@ static inline int look_for_irix_interpreter(char **name,
        struct file *file = NULL;
 
        *name = NULL;
-       for(i = 0; i < pnum; i++, epp++) {
+       for (i = 0; i < pnum; i++, epp++) {
                if (epp->p_type != PT_INTERP)
                        continue;
 
@@ -467,8 +504,8 @@ static inline void map_executable(struct file *fp, struct elf_phdr *epp, int pnu
        unsigned int tmp;
        int i, prot;
 
-       for(i = 0; i < pnum; i++, epp++) {
-               if(epp->p_type != PT_LOAD)
+       for (i = 0; i < pnum; i++, epp++) {
+               if (epp->p_type != PT_LOAD)
                        continue;
 
                /* Map it. */
@@ -483,23 +520,23 @@ static inline void map_executable(struct file *fp, struct elf_phdr *epp, int pnu
                up_write(&current->mm->mmap_sem);
 
                /* Fixup location tracking vars. */
-               if((epp->p_vaddr & 0xfffff000) < *estack)
+               if ((epp->p_vaddr & 0xfffff000) < *estack)
                        *estack = (epp->p_vaddr & 0xfffff000);
-               if(!*laddr)
+               if (!*laddr)
                        *laddr = epp->p_vaddr - epp->p_offset;
-               if(epp->p_vaddr < *scode)
+               if (epp->p_vaddr < *scode)
                        *scode = epp->p_vaddr;
 
                tmp = epp->p_vaddr + epp->p_filesz;
-               if(tmp > *ebss)
+               if (tmp > *ebss)
                        *ebss = tmp;
-               if((epp->p_flags & PF_X) && *ecode < tmp)
+               if ((epp->p_flags & PF_X) && *ecode < tmp)
                        *ecode = tmp;
-               if(*edata < tmp)
+               if (*edata < tmp)
                        *edata = tmp;
 
                tmp = epp->p_vaddr + epp->p_memsz;
-               if(tmp > *ebrk)
+               if (tmp > *ebrk)
                        *ebrk = tmp;
        }
 
@@ -513,12 +550,12 @@ static inline int map_interpreter(struct elf_phdr *epp, struct elfhdr *ihp,
        int i;
 
        *eentry = 0xffffffff;
-       for(i = 0; i < pnum; i++, epp++) {
-               if(epp->p_type != PT_INTERP)
+       for (i = 0; i < pnum; i++, epp++) {
+               if (epp->p_type != PT_INTERP)
                        continue;
 
                /* We should have fielded this error elsewhere... */
-               if(*eentry != 0xffffffff)
+               if (*eentry != 0xffffffff)
                        return -1;
 
                set_fs(old_fs);
@@ -604,9 +641,7 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        if (elf_ex.e_shnum > 20)
                goto out;
 
-#ifdef DEBUG
        print_elfhdr(&elf_ex);
-#endif
 
        /* Now read in all of the header information */
        size = elf_ex.e_phentsize * elf_ex.e_phnum;
@@ -622,13 +657,11 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
        if (retval < 0)
                goto out_free_ph;
 
-#ifdef DEBUG
        dump_phdrs(elf_phdata, elf_ex.e_phnum);
-#endif
 
        /* Set some things for later. */
-       for(i = 0; i < elf_ex.e_phnum; i++) {
-               switch(elf_phdata[i].p_type) {
+       for (i = 0; i < elf_ex.e_phnum; i++) {
+               switch (elf_phdata[i].p_type) {
                case PT_INTERP:
                        has_interp = 1;
                        elf_ihdr = &elf_phdata[i];
@@ -667,7 +700,7 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
 
        if (elf_interpreter) {
                retval = verify_irix_interpreter(&interp_elf_ex);
-               if(retval)
+               if (retval)
                        goto out_free_interp;
        }
 
@@ -706,12 +739,12 @@ static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs)
                       &load_addr, &start_code, &elf_bss, &end_code,
                       &end_data, &elf_brk);
 
-       if(elf_interpreter) {
+       if (elf_interpreter) {
                retval = map_interpreter(elf_phdata, &interp_elf_ex,
                                         interpreter, &interp_load_addr,
                                         elf_ex.e_phnum, old_fs, &elf_entry);
                kfree(elf_interpreter);
-               if(retval) {
+               if (retval) {
                        set_fs(old_fs);
                        printk("Unable to load IRIX ELF interpreter\n");
                        send_sig(SIGSEGV, current, 0);
@@ -809,12 +842,12 @@ static int load_irix_library(struct file *file)
                return -ENOEXEC;
 
        /* First of all, some simple consistency checks. */
-       if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
+       if (elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
           !file->f_op->mmap)
                return -ENOEXEC;
 
        /* Now read in all of the header information. */
-       if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
+       if (sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
                return -ENOEXEC;
 
        elf_phdata = kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
@@ -825,15 +858,15 @@ static int load_irix_library(struct file *file)
                           sizeof(struct elf_phdr) * elf_ex.e_phnum);
 
        j = 0;
-       for(i=0; i<elf_ex.e_phnum; i++)
-               if((elf_phdata + i)->p_type == PT_LOAD) j++;
+       for (i=0; i<elf_ex.e_phnum; i++)
+               if ((elf_phdata + i)->p_type == PT_LOAD) j++;
 
-       if(j != 1)  {
+       if (j != 1)  {
                kfree(elf_phdata);
                return -ENOEXEC;
        }
 
-       while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
+       while (elf_phdata->p_type != PT_LOAD) elf_phdata++;
 
        /* Now use mmap to map the library into memory. */
        down_write(&current->mm->mmap_sem);
@@ -889,9 +922,7 @@ unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt)
                return -EFAULT;
        }
 
-#ifdef DEBUG
        dump_phdrs(user_phdrp, cnt);
-#endif
 
        for (i = 0; i < cnt; i++, hp++) {
                if (__get_user(type, &hp->p_type))
@@ -905,14 +936,14 @@ unsigned long irix_mapelf(int fd, struct elf_phdr __user *user_phdrp, int cnt)
        filp = fget(fd);
        if (!filp)
                return -EACCES;
-       if(!filp->f_op) {
+       if (!filp->f_op) {
                printk("irix_mapelf: Bogon filp!\n");
                fput(filp);
                return -EACCES;
        }
 
        hp = user_phdrp;
-       for(i = 0; i < cnt; i++, hp++) {
+       for (i = 0; i < cnt; i++, hp++) {
                int prot;
 
                retval = __get_user(vaddr, &hp->p_vaddr);
@@ -1015,8 +1046,6 @@ static int notesize(struct memelfnote *en)
        return sz;
 }
 
-/* #define DEBUG */
-
 #define DUMP_WRITE(addr, nr)   \
        if (!dump_write(file, (addr), (nr))) \
                goto end_coredump;
@@ -1093,9 +1122,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
 
                segs++;
        }
-#ifdef DEBUG
-       printk("irix_core_dump: %d segs taking %d bytes\n", segs, size);
-#endif
+       pr_debug("irix_core_dump: %d segs taking %d bytes\n", segs, size);
 
        /* Set up header. */
        memcpy(elf.e_ident, ELFMAG, SELFMAG);
@@ -1221,7 +1248,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
                struct elf_phdr phdr;
                int sz = 0;
 
-               for(i = 0; i < numnote; i++)
+               for (i = 0; i < numnote; i++)
                        sz += notesize(&notes[i]);
 
                phdr.p_type = PT_NOTE;
@@ -1241,7 +1268,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
        dataoff = offset = roundup(offset, PAGE_SIZE);
 
        /* Write program headers for segments dump. */
-       for(vma = current->mm->mmap, i = 0;
+       for (vma = current->mm->mmap, i = 0;
                i < segs && vma != NULL; vma = vma->vm_next) {
                struct elf_phdr phdr;
                size_t sz;
@@ -1267,7 +1294,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
                DUMP_WRITE(&phdr, sizeof(phdr));
        }
 
-       for(i = 0; i < numnote; i++)
+       for (i = 0; i < numnote; i++)
                if (!writenote(&notes[i], file))
                        goto end_coredump;
 
@@ -1275,7 +1302,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
 
        DUMP_SEEK(dataoff);
 
-       for(i = 0, vma = current->mm->mmap;
+       for (i = 0, vma = current->mm->mmap;
            i < segs && vma != NULL;
            vma = vma->vm_next) {
                unsigned long addr = vma->vm_start;
@@ -1284,9 +1311,7 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
                if (!maydump(vma))
                        continue;
                i++;
-#ifdef DEBUG
-               printk("elf_core_dump: writing %08lx %lx\n", addr, len);
-#endif
+               pr_debug("elf_core_dump: writing %08lx %lx\n", addr, len);
                DUMP_WRITE((void __user *)addr, len);
        }
 
index bcaad66..2967537 100644 (file)
@@ -112,7 +112,7 @@ msc_bind_eic_interrupt (unsigned int irq, unsigned int set)
 }
 
 struct irq_chip msc_levelirq_type = {
-       .typename = "SOC-it-Level",
+       .name = "SOC-it-Level",
        .ack = level_mask_and_ack_msc_irq,
        .mask = mask_msc_irq,
        .mask_ack = level_mask_and_ack_msc_irq,
@@ -122,7 +122,7 @@ struct irq_chip msc_levelirq_type = {
 };
 
 struct irq_chip msc_edgeirq_type = {
-       .typename = "SOC-it-Edge",
+       .name = "SOC-it-Edge",
        .ack = edge_mask_and_ack_msc_irq,
        .mask = mask_msc_irq,
        .mask_ack = edge_mask_and_ack_msc_irq,
index efbd219..3dd5618 100644 (file)
@@ -23,13 +23,13 @@ static unsigned int irq_base;
 
 static inline int ls1bit32(unsigned int x)
 {
-        int b = 31, s;
+       int b = 31, s;
 
-        s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s;
-        s =  8; if (x <<  8 == 0) s = 0; b -= s; x <<= s;
-        s =  4; if (x <<  4 == 0) s = 0; b -= s; x <<= s;
-        s =  2; if (x <<  2 == 0) s = 0; b -= s; x <<= s;
-        s =  1; if (x <<  1 == 0) s = 0; b -= s;
+       s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s;
+       s =  8; if (x <<  8 == 0) s = 0; b -= s; x <<= s;
+       s =  4; if (x <<  4 == 0) s = 0; b -= s; x <<= s;
+       s =  2; if (x <<  2 == 0) s = 0; b -= s; x <<= s;
+       s =  1; if (x <<  1 == 0) s = 0; b -= s;
 
         return b;
 }
@@ -92,7 +92,7 @@ void ll_mv64340_irq(void)
 }
 
 struct irq_chip mv64340_irq_type = {
-       .typename = "MV-64340",
+       .name = "MV-64340",
        .ack = mask_mv64340_irq,
        .mask = mask_mv64340_irq,
        .mask_ack = mask_mv64340_irq,
index 123324b..2507328 100644 (file)
 #include <asm/mipsregs.h>
 #include <asm/system.h>
 
-static int irq_base;
-
 static inline void unmask_rm7k_irq(unsigned int irq)
 {
-       set_c0_intcontrol(0x100 << (irq - irq_base));
+       set_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE));
 }
 
 static inline void mask_rm7k_irq(unsigned int irq)
 {
-       clear_c0_intcontrol(0x100 << (irq - irq_base));
+       clear_c0_intcontrol(0x100 << (irq - RM7K_CPU_IRQ_BASE));
 }
 
 static struct irq_chip rm7k_irq_controller = {
-       .typename = "RM7000",
+       .name = "RM7000",
        .ack = mask_rm7k_irq,
        .mask = mask_rm7k_irq,
        .mask_ack = mask_rm7k_irq,
        .unmask = unmask_rm7k_irq,
 };
 
-void __init rm7k_cpu_irq_init(int base)
+void __init rm7k_cpu_irq_init(void)
 {
+       int base = RM7K_CPU_IRQ_BASE;
        int i;
 
        clear_c0_intcontrol(0x00000f00);                /* Mask all */
@@ -46,6 +45,4 @@ void __init rm7k_cpu_irq_init(int base)
        for (i = base; i < base + 4; i++)
                set_irq_chip_and_handler(i, &rm7k_irq_controller,
                                         handle_level_irq);
-
-       irq_base = base;
 }
index 0e6f4c5..ae83d2d 100644 (file)
 #include <asm/mipsregs.h>
 #include <asm/system.h>
 
-static int irq_base;
-
 static inline void unmask_rm9k_irq(unsigned int irq)
 {
-       set_c0_intcontrol(0x1000 << (irq - irq_base));
+       set_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE));
 }
 
 static inline void mask_rm9k_irq(unsigned int irq)
 {
-       clear_c0_intcontrol(0x1000 << (irq - irq_base));
+       clear_c0_intcontrol(0x1000 << (irq - RM9K_CPU_IRQ_BASE));
 }
 
 static inline void rm9k_cpu_irq_enable(unsigned int irq)
@@ -39,15 +37,6 @@ static inline void rm9k_cpu_irq_enable(unsigned int irq)
        local_irq_restore(flags);
 }
 
-static void rm9k_cpu_irq_disable(unsigned int irq)
-{
-       unsigned long flags;
-
-       local_irq_save(flags);
-       mask_rm9k_irq(irq);
-       local_irq_restore(flags);
-}
-
 /*
  * Performance counter interrupts are global on all processors.
  */
@@ -81,7 +70,7 @@ static void rm9k_perfcounter_irq_shutdown(unsigned int irq)
 }
 
 static struct irq_chip rm9k_irq_controller = {
-       .typename = "RM9000",
+       .name = "RM9000",
        .ack = mask_rm9k_irq,
        .mask = mask_rm9k_irq,
        .mask_ack = mask_rm9k_irq,
@@ -89,7 +78,7 @@ static struct irq_chip rm9k_irq_controller = {
 };
 
 static struct irq_chip rm9k_perfcounter_irq = {
-       .typename = "RM9000",
+       .name = "RM9000",
        .startup = rm9k_perfcounter_irq_startup,
        .shutdown = rm9k_perfcounter_irq_shutdown,
        .ack = mask_rm9k_irq,
@@ -102,8 +91,9 @@ unsigned int rm9000_perfcount_irq;
 
 EXPORT_SYMBOL(rm9000_perfcount_irq);
 
-void __init rm9k_cpu_irq_init(int base)
+void __init rm9k_cpu_irq_init(void)
 {
+       int base = RM9K_CPU_IRQ_BASE;
        int i;
 
        clear_c0_intcontrol(0x0000f000);                /* Mask all */
@@ -115,6 +105,4 @@ void __init rm9k_cpu_irq_init(int base)
        rm9000_perfcount_irq = base + 1;
        set_irq_chip_and_handler(rm9000_perfcount_irq, &rm9k_perfcounter_irq,
                                 handle_level_irq);
-
-       irq_base = base;
 }
index fcc86b9..7b66e03 100644 (file)
@@ -25,7 +25,7 @@
  * Don't even think about using this on SMP.  You have been warned.
  *
  * This file exports one global function:
- *     void mips_cpu_irq_init(int irq_base);
+ *     void mips_cpu_irq_init(void);
  */
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <asm/mipsmtregs.h>
 #include <asm/system.h>
 
-static int mips_cpu_irq_base;
-
 static inline void unmask_mips_irq(unsigned int irq)
 {
-       set_c0_status(0x100 << (irq - mips_cpu_irq_base));
+       set_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE));
        irq_enable_hazard();
 }
 
 static inline void mask_mips_irq(unsigned int irq)
 {
-       clear_c0_status(0x100 << (irq - mips_cpu_irq_base));
+       clear_c0_status(0x100 << (irq - MIPS_CPU_IRQ_BASE));
        irq_disable_hazard();
 }
 
 static struct irq_chip mips_cpu_irq_controller = {
-       .typename       = "MIPS",
+       .name           = "MIPS",
        .ack            = mask_mips_irq,
        .mask           = mask_mips_irq,
        .mask_ack       = mask_mips_irq,
@@ -70,7 +68,7 @@ static unsigned int mips_mt_cpu_irq_startup(unsigned int irq)
 {
        unsigned int vpflags = dvpe();
 
-       clear_c0_cause(0x100 << (irq - mips_cpu_irq_base));
+       clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE));
        evpe(vpflags);
        unmask_mips_mt_irq(irq);
 
@@ -84,13 +82,13 @@ static unsigned int mips_mt_cpu_irq_startup(unsigned int irq)
 static void mips_mt_cpu_irq_ack(unsigned int irq)
 {
        unsigned int vpflags = dvpe();
-       clear_c0_cause(0x100 << (irq - mips_cpu_irq_base));
+       clear_c0_cause(0x100 << (irq - MIPS_CPU_IRQ_BASE));
        evpe(vpflags);
        mask_mips_mt_irq(irq);
 }
 
 static struct irq_chip mips_mt_cpu_irq_controller = {
-       .typename       = "MIPS",
+       .name           = "MIPS",
        .startup        = mips_mt_cpu_irq_startup,
        .ack            = mips_mt_cpu_irq_ack,
        .mask           = mask_mips_mt_irq,
@@ -99,8 +97,9 @@ static struct irq_chip mips_mt_cpu_irq_controller = {
        .eoi            = unmask_mips_mt_irq,
 };
 
-void __init mips_cpu_irq_init(int irq_base)
+void __init mips_cpu_irq_init(void)
 {
+       int irq_base = MIPS_CPU_IRQ_BASE;
        int i;
 
        /* Mask interrupts. */
@@ -118,6 +117,4 @@ void __init mips_cpu_irq_init(int irq_base)
        for (i = irq_base + 2; i < irq_base + 8; i++)
                set_irq_chip_and_handler(i, &mips_cpu_irq_controller,
                                         handle_level_irq);
-
-       mips_cpu_irq_base = irq_base;
 }
index de3fae2..0b8ce59 100644 (file)
@@ -194,15 +194,15 @@ sysn32_waitid(int which, compat_pid_t pid,
 }
 
 struct sysinfo32 {
-        s32 uptime;
-        u32 loads[3];
-        u32 totalram;
-        u32 freeram;
-        u32 sharedram;
-        u32 bufferram;
-        u32 totalswap;
-        u32 freeswap;
-        u16 procs;
+       s32 uptime;
+       u32 loads[3];
+       u32 totalram;
+       u32 freeram;
+       u32 sharedram;
+       u32 bufferram;
+       u32 totalswap;
+       u32 freeswap;
+       u16 procs;
        u32 totalhigh;
        u32 freehigh;
        u32 mem_unit;
@@ -558,7 +558,7 @@ extern asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf);
 asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32)
 {
        int err;
-        struct ustat tmp;
+       struct ustat tmp;
        struct ustat32 tmp32;
        mm_segment_t old_fs = get_fs();
 
@@ -569,11 +569,11 @@ asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32)
        if (err)
                goto out;
 
-        memset(&tmp32,0,sizeof(struct ustat32));
-        tmp32.f_tfree = tmp.f_tfree;
-        tmp32.f_tinode = tmp.f_tinode;
+       memset(&tmp32,0,sizeof(struct ustat32));
+       tmp32.f_tfree = tmp.f_tfree;
+       tmp32.f_tinode = tmp.f_tinode;
 
-        err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0;
+       err = copy_to_user(ubuf32,&tmp32,sizeof(struct ustat32)) ? -EFAULT : 0;
 
 out:
        return err;
index c1373a6..a32f679 100644 (file)
@@ -96,6 +96,10 @@ asmlinkage long mipsmt_sys_sched_setaffinity(pid_t pid, unsigned int len,
                goto out_unlock;
        }
 
+       retval = security_task_setscheduler(p, 0, NULL);
+       if (retval)
+               goto out_unlock;
+
        /* Record new user-specified CPU set for future reference */
        p->thread.user_cpus_allowed = new_mask;
 
@@ -141,8 +145,9 @@ asmlinkage long mipsmt_sys_sched_getaffinity(pid_t pid, unsigned int len,
        p = find_process_by_pid(pid);
        if (!p)
                goto out_unlock;
-
-       retval = 0;
+       retval = security_task_getscheduler(p);
+       if (retval)
+               goto out_unlock;
 
        cpus_and(mask, p->thread.user_cpus_allowed, cpu_possible_map);
 
index 4ed37ba..5ddc2e9 100644 (file)
@@ -31,13 +31,13 @@ static const char *cpu_name[] = {
        [CPU_R4000PC]   = "R4000PC",
        [CPU_R4000SC]   = "R4000SC",
        [CPU_R4000MC]   = "R4000MC",
-        [CPU_R4200]    = "R4200",
+       [CPU_R4200]     = "R4200",
        [CPU_R4400PC]   = "R4400PC",
        [CPU_R4400SC]   = "R4400SC",
        [CPU_R4400MC]   = "R4400MC",
        [CPU_R4600]     = "R4600",
        [CPU_R6000]     = "R6000",
-        [CPU_R6000A]   = "R6000A",
+       [CPU_R6000A]    = "R6000A",
        [CPU_R8000]     = "R8000",
        [CPU_R10000]    = "R10000",
        [CPU_R12000]    = "R12000",
@@ -46,14 +46,14 @@ static const char *cpu_name[] = {
        [CPU_R4650]     = "R4650",
        [CPU_R4700]     = "R4700",
        [CPU_R5000]     = "R5000",
-        [CPU_R5000A]   = "R5000A",
+       [CPU_R5000A]    = "R5000A",
        [CPU_R4640]     = "R4640",
        [CPU_NEVADA]    = "Nevada",
        [CPU_RM7000]    = "RM7000",
        [CPU_RM9000]    = "RM9000",
        [CPU_R5432]     = "R5432",
        [CPU_4KC]       = "MIPS 4Kc",
-        [CPU_5KC]      = "MIPS 5Kc",
+       [CPU_5KC]       = "MIPS 5Kc",
        [CPU_R4310]     = "R4310",
        [CPU_SB1]       = "SiByte SB1",
        [CPU_SB1A]      = "SiByte SB1A",
index ec8209f..04e5b38 100644 (file)
 #include <asm/isadep.h>
 #include <asm/inst.h>
 #include <asm/stacktrace.h>
-#ifdef CONFIG_MIPS_MT_SMTC
-#include <asm/mipsmtregs.h>
-extern void smtc_idle_loop_hook(void);
-#endif /* CONFIG_MIPS_MT_SMTC */
 
 /*
  * The idle thread. There's no useful work to be done, so just try to conserve
@@ -57,6 +53,8 @@ ATTRIB_NORET void cpu_idle(void)
        while (1) {
                while (!need_resched()) {
 #ifdef CONFIG_MIPS_MT_SMTC
+                       extern void smtc_idle_loop_hook(void);
+
                        smtc_idle_loop_hook();
 #endif /* CONFIG_MIPS_MT_SMTC */
                        if (cpu_wait)
index 880fa6e..59c1577 100644 (file)
@@ -114,6 +114,14 @@ LEAF(_save_fp_context32)
  */
 LEAF(_restore_fp_context)
        EX      lw t0, SC_FPC_CSR(a0)
+
+       /* Fail if the CSR has exceptions pending */
+       srl     t1, t0, 5
+       and     t1, t0
+       andi    t1, 0x1f << 7
+       bnez    t1, fault
+        nop
+
 #ifdef CONFIG_64BIT
        EX      ldc1 $f1, SC_FPREGS+8(a0)
        EX      ldc1 $f3, SC_FPREGS+24(a0)
@@ -157,6 +165,14 @@ LEAF(_restore_fp_context)
 LEAF(_restore_fp_context32)
        /* Restore an o32 sigcontext.  */
        EX      lw t0, SC32_FPC_CSR(a0)
+
+       /* Fail if the CSR has exceptions pending */
+       srl     t1, t0, 5
+       and     t1, t0
+       andi    t1, 0x1f << 7
+       bnez    t1, fault
+        nop
+
        EX      ldc1 $f0, SC32_FPREGS+0(a0)
        EX      ldc1 $f2, SC32_FPREGS+16(a0)
        EX      ldc1 $f4, SC32_FPREGS+32(a0)
@@ -177,9 +193,10 @@ LEAF(_restore_fp_context32)
        jr      ra
         li     v0, 0                                   # success
        END(_restore_fp_context32)
-       .set    reorder
 #endif
 
+       .set    reorder
+
        .type   fault@function
        .ent    fault
 fault: li      v0, -EFAULT                             # failure
index 5a99e3e..8610f4a 100644 (file)
@@ -63,7 +63,7 @@ extern void *vpe_get_shared(int index);
 
 static void rtlx_dispatch(void)
 {
-       do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ);
+       do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ);
 }
 
 
@@ -491,7 +491,7 @@ static struct irqaction rtlx_irq = {
        .name           = "RTLX",
 };
 
-static int rtlx_irq_num = MIPSCPU_INT_BASE + MIPS_CPU_RTLX_IRQ;
+static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ;
 
 static char register_chrdev_failed[] __initdata =
        KERN_ERR "rtlx_module_init: unable to register device\n";
index a7bff2a..39add23 100644 (file)
@@ -384,7 +384,7 @@ EXPORT(sysn32_call_table)
        PTR     sys_readlinkat
        PTR     sys_fchmodat
        PTR     sys_faccessat
-       PTR     sys_pselect6
+       PTR     compat_sys_pselect6
        PTR     sys_ppoll                       /* 6265 */
        PTR     sys_unshare
        PTR     sys_splice
index e91379c..c58b8e0 100644 (file)
@@ -506,7 +506,7 @@ sys_call_table:
        PTR     sys_readlinkat
        PTR     sys_fchmodat
        PTR     sys_faccessat                   /* 4300 */
-       PTR     sys_pselect6
+       PTR     compat_sys_pselect6
        PTR     sys_ppoll
        PTR     sys_unshare
        PTR     sys_splice
index 89440a0..d2e01e7 100644 (file)
@@ -271,8 +271,7 @@ static void __init bootmem_init(void)
 static void __init bootmem_init(void)
 {
        unsigned long reserved_end;
-       unsigned long highest = 0;
-       unsigned long mapstart = -1UL;
+       unsigned long mapstart = ~0UL;
        unsigned long bootmap_size;
        int i;
 
@@ -283,6 +282,13 @@ static void __init bootmem_init(void)
         */
        reserved_end = max(init_initrd(), PFN_UP(__pa_symbol(&_end)));
 
+       /*
+        * max_low_pfn is not a number of pages. The number of pages
+        * of the system is given by 'max_low_pfn - min_low_pfn'.
+        */
+       min_low_pfn = ~0UL;
+       max_low_pfn = 0;
+
        /*
         * Find the highest page frame number we have available.
         */
@@ -296,8 +302,10 @@ static void __init bootmem_init(void)
                end = PFN_DOWN(boot_mem_map.map[i].addr
                                + boot_mem_map.map[i].size);
 
-               if (end > highest)
-                       highest = end;
+               if (end > max_low_pfn)
+                       max_low_pfn = end;
+               if (start < min_low_pfn)
+                       min_low_pfn = start;
                if (end <= reserved_end)
                        continue;
                if (start >= mapstart)
@@ -305,22 +313,36 @@ static void __init bootmem_init(void)
                mapstart = max(reserved_end, start);
        }
 
+       if (min_low_pfn >= max_low_pfn)
+               panic("Incorrect memory mapping !!!");
+       if (min_low_pfn > ARCH_PFN_OFFSET) {
+               printk(KERN_INFO
+                      "Wasting %lu bytes for tracking %lu unused pages\n",
+                      (min_low_pfn - ARCH_PFN_OFFSET) * sizeof(struct page),
+                      min_low_pfn - ARCH_PFN_OFFSET);
+       } else if (min_low_pfn < ARCH_PFN_OFFSET) {
+               printk(KERN_INFO
+                      "%lu free pages won't be used\n",
+                      ARCH_PFN_OFFSET - min_low_pfn);
+       }
+       min_low_pfn = ARCH_PFN_OFFSET;
+
        /*
         * Determine low and high memory ranges
         */
-       if (highest > PFN_DOWN(HIGHMEM_START)) {
+       if (max_low_pfn > PFN_DOWN(HIGHMEM_START)) {
 #ifdef CONFIG_HIGHMEM
                highstart_pfn = PFN_DOWN(HIGHMEM_START);
-               highend_pfn = highest;
+               highend_pfn = max_low_pfn;
 #endif
-               highest = PFN_DOWN(HIGHMEM_START);
+               max_low_pfn = PFN_DOWN(HIGHMEM_START);
        }
 
        /*
         * Initialize the boot-time allocator with low memory only.
         */
-       bootmap_size = init_bootmem(mapstart, highest);
-
+       bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,
+                                        min_low_pfn, max_low_pfn);
        /*
         * Register fully available low RAM pages with the bootmem allocator.
         */
@@ -507,9 +529,9 @@ void __init setup_arch(char **cmdline_p)
 
 #if defined(CONFIG_VT)
 #if defined(CONFIG_VGA_CONSOLE)
-        conswitchp = &vga_con;
+       conswitchp = &vga_con;
 #elif defined(CONFIG_DUMMY_CONSOLE)
-        conswitchp = &dummy_con;
+       conswitchp = &dummy_con;
 #endif
 #endif
 
@@ -541,3 +563,6 @@ int __init dsp_disable(char *s)
 }
 
 __setup("nodsp", dsp_disable);
+
+unsigned long kernelsp[NR_CPUS];
+unsigned long fw_arg0, fw_arg1, fw_arg2, fw_arg3;
index b9d358e..9a44053 100644 (file)
@@ -89,7 +89,7 @@ _sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
        spin_lock_irq(&current->sighand->siglock);
        current->saved_sigmask = current->blocked;
        current->blocked = newset;
-        recalc_sigpending();
+       recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
 
        current->state = TASK_INTERRUPTIBLE;
@@ -124,7 +124,7 @@ asmlinkage int sys_sigaction(int sig, const struct sigaction __user *act,
 
        if (!ret && oact) {
                if (!access_ok(VERIFY_WRITE, oact, sizeof(*oact)))
-                        return -EFAULT;
+                       return -EFAULT;
                err |= __put_user(old_ka.sa.sa_flags, &oact->sa_flags);
                err |= __put_user(old_ka.sa.sa_handler, &oact->sa_handler);
                err |= __put_user(old_ka.sa.sa_mask.sig[0], oact->sa_mask.sig);
@@ -304,7 +304,7 @@ int setup_frame(struct k_sigaction * ka, struct pt_regs *regs,
               current->comm, current->pid,
               frame, regs->cp0_epc, frame->regs[31]);
 #endif
-        return 0;
+       return 0;
 
 give_sigsegv:
        force_sigsegv(signr, current);
index a67c185..b28646b 100644 (file)
@@ -105,7 +105,7 @@ _sysn32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
        spin_lock_irq(&current->sighand->siglock);
        current->saved_sigmask = current->blocked;
        current->blocked = newset;
-        recalc_sigpending();
+       recalc_sigpending();
        spin_unlock_irq(&current->sighand->siglock);
 
        current->state = TASK_INTERRUPTIBLE;
@@ -184,7 +184,7 @@ int setup_rt_frame_n32(struct k_sigaction * ka,
        /* Create the ucontext.  */
        err |= __put_user(0, &frame->rs_uc.uc_flags);
        err |= __put_user(0, &frame->rs_uc.uc_link);
-        sp = (int) (long) current->sas_ss_sp;
+       sp = (int) (long) current->sas_ss_sp;
        err |= __put_user(sp,
                          &frame->rs_uc.uc_stack.ss_sp);
        err |= __put_user(sas_ss_flags(regs->regs[29]),
index 1ee689c..64b62bd 100644 (file)
@@ -35,7 +35,6 @@
 #include <asm/mipsregs.h>
 #include <asm/mipsmtregs.h>
 #include <asm/mips_mt.h>
-#include <asm/mips-boards/maltaint.h>  /* This is f*cking wrong */
 
 #define MIPS_CPU_IPI_RESCHED_IRQ 0
 #define MIPS_CPU_IPI_CALL_IRQ 1
@@ -108,12 +107,12 @@ void __init sanitize_tlb_entries(void)
 
 static void ipi_resched_dispatch(void)
 {
-       do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
+       do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ);
 }
 
 static void ipi_call_dispatch(void)
 {
-       do_IRQ(MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ);
+       do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ);
 }
 
 static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
@@ -270,8 +269,8 @@ void __init plat_prepare_cpus(unsigned int max_cpus)
                set_vi_handler(MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
        }
 
-       cpu_ipi_resched_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
-       cpu_ipi_call_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_CALL_IRQ;
+       cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
+       cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ;
 
        setup_irq(cpu_ipi_resched_irq, &irq_resched);
        setup_irq(cpu_ipi_call_irq, &irq_call);
index 6a857bf..9251ea8 100644 (file)
  * This file should be built into the kernel only if CONFIG_MIPS_MT_SMTC is set.
  */
 
-/*
- * MIPSCPU_INT_BASE is identically defined in both
- * asm-mips/mips-boards/maltaint.h and asm-mips/mips-boards/simint.h,
- * but as yet there's no properly organized include structure that
- * will ensure that the right *int.h file will be included for a
- * given platform build.
- */
-
-#define MIPSCPU_INT_BASE       16
-
 #define MIPS_CPU_IPI_IRQ       1
 
 #define LOCK_MT_PRA() \
@@ -77,15 +67,15 @@ unsigned int ipi_timer_latch[NR_CPUS];
 
 #define IPIBUF_PER_CPU 4
 
-struct smtc_ipi_q IPIQ[NR_CPUS];
-struct smtc_ipi_q freeIPIq;
+static struct smtc_ipi_q IPIQ[NR_CPUS];
+static struct smtc_ipi_q freeIPIq;
 
 
 /* Forward declarations */
 
 void ipi_decode(struct smtc_ipi *);
-void post_direct_ipi(int cpu, struct smtc_ipi *pipi);
-void setup_cross_vpe_interrupts(void);
+static void post_direct_ipi(int cpu, struct smtc_ipi *pipi);
+static void setup_cross_vpe_interrupts(void);
 void init_smtc_stats(void);
 
 /* Global SMTC Status */
@@ -200,7 +190,7 @@ void __init sanitize_tlb_entries(void)
  * Configure shared TLB - VPC configuration bit must be set by caller
  */
 
-void smtc_configure_tlb(void)
+static void smtc_configure_tlb(void)
 {
        int i,tlbsiz,vpes;
        unsigned long mvpconf0;
@@ -648,7 +638,7 @@ int setup_irq_smtc(unsigned int irq, struct irqaction * new,
  * the VPE.
  */
 
-void smtc_ipi_qdump(void)
+static void smtc_ipi_qdump(void)
 {
        int i;
 
@@ -686,28 +676,6 @@ static __inline__ int atomic_postincrement(unsigned int *pv)
        return result;
 }
 
-/* No longer used in IPI dispatch, but retained for future recycling */
-
-static __inline__ int atomic_postclear(unsigned int *pv)
-{
-       unsigned long result;
-
-       unsigned long temp;
-
-       __asm__ __volatile__(
-       "1:     ll      %0, %2                                  \n"
-       "       or      %1, $0, $0                              \n"
-       "       sc      %1, %2                                  \n"
-       "       beqz    %1, 1b                                  \n"
-       "       sync                                            \n"
-       : "=&r" (result), "=&r" (temp), "=m" (*pv)
-       : "m" (*pv)
-       : "memory");
-
-       return result;
-}
-
-
 void smtc_send_ipi(int cpu, int type, unsigned int action)
 {
        int tcstatus;
@@ -781,7 +749,7 @@ void smtc_send_ipi(int cpu, int type, unsigned int action)
 /*
  * Send IPI message to Halted TC, TargTC/TargVPE already having been set
  */
-void post_direct_ipi(int cpu, struct smtc_ipi *pipi)
+static void post_direct_ipi(int cpu, struct smtc_ipi *pipi)
 {
        struct pt_regs *kstack;
        unsigned long tcstatus;
@@ -921,7 +889,7 @@ void smtc_timer_broadcast(int vpe)
  * interrupts.
  */
 
-static int cpu_ipi_irq = MIPSCPU_INT_BASE + MIPS_CPU_IPI_IRQ;
+static int cpu_ipi_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_IRQ;
 
 static irqreturn_t ipi_interrupt(int irq, void *dev_idm)
 {
@@ -1000,7 +968,7 @@ static void ipi_irq_dispatch(void)
 
 static struct irqaction irq_ipi;
 
-void setup_cross_vpe_interrupts(void)
+static void setup_cross_vpe_interrupts(void)
 {
        if (!cpu_has_vint)
                panic("SMTC Kernel requires Vectored Interupt support");
@@ -1191,7 +1159,7 @@ void smtc_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu)
         * It would be nice to be able to use a spinlock here,
         * but this is invoked from within TLB flush routines
         * that protect themselves with DVPE, so if a lock is
-         * held by another TC, it'll never be freed.
+        * held by another TC, it'll never be freed.
         *
         * DVPE/DMT must not be done with interrupts enabled,
         * so even so most callers will already have disabled
@@ -1296,7 +1264,7 @@ void smtc_flush_tlb_asid(unsigned long asid)
  * Support for single-threading cache flush operations.
  */
 
-int halt_state_save[NR_CPUS];
+static int halt_state_save[NR_CPUS];
 
 /*
  * To really, really be sure that nothing is being done
index 6c2406a..93a1484 100644 (file)
@@ -669,7 +669,7 @@ asmlinkage int irix_mount(char __user *dev_name, char __user *dir_name,
 
 struct irix_statfs {
        short f_type;
-        long  f_bsize, f_frsize, f_blocks, f_bfree, f_files, f_ffree;
+       long  f_bsize, f_frsize, f_blocks, f_bfree, f_files, f_ffree;
        char  f_fname[6], f_fpack[6];
 };
 
@@ -959,7 +959,7 @@ static inline loff_t llseek(struct file *file, loff_t offset, int origin)
 
        fn = default_llseek;
        if (file->f_op && file->f_op->llseek)
-        fn = file->f_op->llseek;
+       fn = file->f_op->llseek;
        lock_kernel();
        retval = fn(file, offset, origin);
        unlock_kernel();
index 458fccf..4596249 100644 (file)
@@ -522,7 +522,7 @@ static int (*reloc_handlers[]) (struct module *me, uint32_t *location,
 };
 
 static char *rstrs[] = {
-       [R_MIPS_NONE]   = "MIPS_NONE",
+       [R_MIPS_NONE]   = "MIPS_NONE",
        [R_MIPS_32]     = "MIPS_32",
        [R_MIPS_26]     = "MIPS_26",
        [R_MIPS_HI16]   = "MIPS_HI16",
@@ -695,7 +695,7 @@ static void dump_tclist(void)
 }
 
 /* We are prepared so configure and start the VPE... */
-int vpe_run(struct vpe * v)
+static int vpe_run(struct vpe * v)
 {
        struct vpe_notifications *n;
        unsigned long val, dmt_flag;
@@ -713,16 +713,16 @@ int vpe_run(struct vpe * v)
        dvpe();
 
        if (!list_empty(&v->tc)) {
-                if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
-                        printk(KERN_WARNING "VPE loader: TC %d is already in use.\n",
-                               t->index);
-                        return -ENOEXEC;
-                }
-        } else {
-                printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n",
-                       v->minor);
-                return -ENOEXEC;
-        }
+               if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
+                       printk(KERN_WARNING "VPE loader: TC %d is already in use.\n",
+                              t->index);
+                       return -ENOEXEC;
+               }
+       } else {
+               printk(KERN_WARNING "VPE loader: No TC's associated with VPE %d\n",
+                      v->minor);
+               return -ENOEXEC;
+       }
 
        /* Put MVPE's into 'configuration state' */
        set_c0_mvpcontrol(MVPCONTROL_VPC);
@@ -775,14 +775,14 @@ int vpe_run(struct vpe * v)
 
        back_to_back_c0_hazard();
 
-        /* Set up the XTC bit in vpeconf0 to point at our tc */
-        write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
-                               | (t->index << VPECONF0_XTC_SHIFT));
+       /* Set up the XTC bit in vpeconf0 to point at our tc */
+       write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
+                             | (t->index << VPECONF0_XTC_SHIFT));
 
        back_to_back_c0_hazard();
 
-        /* enable this VPE */
-        write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
+       /* enable this VPE */
+       write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
 
        /* clear out any left overs from a previous program */
        write_vpe_c0_status(0);
@@ -832,7 +832,7 @@ static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
  * contents of the program (p)buffer performing relocatations/etc, free's it
  * when finished.
  */
-int vpe_elfload(struct vpe * v)
+static int vpe_elfload(struct vpe * v)
 {
        Elf_Ehdr *hdr;
        Elf_Shdr *sechdrs;
index 2affa5f..9a622b9 100644 (file)
@@ -45,7 +45,7 @@ void enable_lasat_irq(unsigned int irq_nr)
 }
 
 static struct irq_chip lasat_irq_type = {
-       .typename = "Lasat",
+       .name = "Lasat",
        .ack = disable_lasat_irq,
        .mask = disable_lasat_irq,
        .mask_ack = disable_lasat_irq,
index 88c7ab8..d47692f 100644 (file)
@@ -132,9 +132,8 @@ void __init prom_init(void)
        add_memory_region(0, lasat_board_info.li_memsize, BOOT_MEM_RAM);
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
 
 const char *get_system_type(void)
index dcd4d2e..2036cf5 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for MIPS-specific library files..
 #
 
-lib-y  += memset.o watch.o
+lib-y  += watch.o
 
 obj-$(CONFIG_CPU_MIPS32)       += dump_tlb.o
 obj-$(CONFIG_CPU_MIPS64)       += dump_tlb.o
diff --git a/arch/mips/lib-32/memset.S b/arch/mips/lib-32/memset.S
deleted file mode 100644 (file)
index 1981485..0000000
+++ /dev/null
@@ -1,145 +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) 1998, 1999, 2000 by Ralf Baechle
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#include <asm/asm.h>
-#include <asm/asm-offsets.h>
-#include <asm/regdef.h>
-
-#define EX(insn,reg,addr,handler)                      \
-9:     insn    reg, addr;                              \
-       .section __ex_table,"a";                        \
-       PTR     9b, handler;                            \
-       .previous
-
-       .macro  f_fill64 dst, offset, val, fixup
-       EX(LONG_S, \val, (\offset +  0 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  1 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  2 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  3 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  4 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  5 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  6 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  7 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  8 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  9 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset + 10 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset + 11 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset + 12 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset + 13 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset + 14 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset + 15 * LONGSIZE)(\dst), \fixup)
-       .endm
-
-/*
- * memset(void *s, int c, size_t n)
- *
- * a0: start of area to clear
- * a1: char to fill with
- * a2: size of area to clear
- */
-       .set    noreorder
-       .align  5
-LEAF(memset)
-       beqz            a1, 1f
-        move           v0, a0                  /* result */
-
-       andi            a1, 0xff                /* spread fillword */
-       sll             t1, a1, 8
-       or              a1, t1
-       sll             t1, a1, 16
-       or              a1, t1
-1:
-
-FEXPORT(__bzero)
-       sltiu           t0, a2, LONGSIZE        /* very small region? */
-       bnez            t0, small_memset
-        andi           t0, a0, LONGMASK        /* aligned? */
-
-       beqz            t0, 1f
-        PTR_SUBU       t0, LONGSIZE            /* alignment in bytes */
-
-#ifdef __MIPSEB__
-       EX(swl, a1, (a0), first_fixup)          /* make word aligned */
-#endif
-#ifdef __MIPSEL__
-       EX(swr, a1, (a0), first_fixup)          /* make word aligned */
-#endif
-       PTR_SUBU        a0, t0                  /* long align ptr */
-       PTR_ADDU        a2, t0                  /* correct size */
-
-1:     ori             t1, a2, 0x3f            /* # of full blocks */
-       xori            t1, 0x3f
-       beqz            t1, memset_partial      /* no block to fill */
-        andi           t0, a2, 0x3c
-
-       PTR_ADDU        t1, a0                  /* end address */
-       .set            reorder
-1:     PTR_ADDIU       a0, 64
-       f_fill64 a0, -64, a1, fwd_fixup
-       bne             t1, a0, 1b
-       .set            noreorder
-
-memset_partial:
-       PTR_LA          t1, 2f                  /* where to start */
-       PTR_SUBU        t1, t0
-       jr              t1
-        PTR_ADDU       a0, t0                  /* dest ptr */
-
-       .set            push
-       .set            noreorder
-       .set            nomacro
-       f_fill64 a0, -64, a1, partial_fixup     /* ... but first do longs ... */
-2:     .set            pop
-       andi            a2, LONGMASK            /* At most one long to go */
-
-       beqz            a2, 1f
-        PTR_ADDU       a0, a2                  /* What's left */
-#ifdef __MIPSEB__
-       EX(swr, a1, -1(a0), last_fixup)
-#endif
-#ifdef __MIPSEL__
-       EX(swl, a1, -1(a0), last_fixup)
-#endif
-1:     jr              ra
-        move           a2, zero
-
-small_memset:
-       beqz            a2, 2f
-        PTR_ADDU       t1, a0, a2
-
-1:     PTR_ADDIU       a0, 1                   /* fill bytewise */
-       bne             t1, a0, 1b
-        sb             a1, -1(a0)
-
-2:     jr              ra                      /* done */
-        move           a2, zero
-       END(memset)
-
-first_fixup:
-       jr      ra
-        nop
-
-fwd_fixup:
-       PTR_L           t0, TI_TASK($28)
-       LONG_L          t0, THREAD_BUADDR(t0)
-       andi            a2, 0x3f
-       LONG_ADDU       a2, t1
-       jr              ra
-        LONG_SUBU      a2, t0
-
-partial_fixup:
-       PTR_L           t0, TI_TASK($28)
-       LONG_L          t0, THREAD_BUADDR(t0)
-       andi            a2, LONGMASK
-       LONG_ADDU       a2, t1
-       jr              ra
-        LONG_SUBU      a2, t0
-
-last_fixup:
-       jr              ra
-        andi           v1, a2, LONGMASK
index dcd4d2e..2036cf5 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for MIPS-specific library files..
 #
 
-lib-y  += memset.o watch.o
+lib-y  += watch.o
 
 obj-$(CONFIG_CPU_MIPS32)       += dump_tlb.o
 obj-$(CONFIG_CPU_MIPS64)       += dump_tlb.o
diff --git a/arch/mips/lib-64/memset.S b/arch/mips/lib-64/memset.S
deleted file mode 100644 (file)
index e2c42c8..0000000
+++ /dev/null
@@ -1,142 +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) 1998, 1999, 2000 by Ralf Baechle
- * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
- */
-#include <asm/asm.h>
-#include <asm/asm-offsets.h>
-#include <asm/regdef.h>
-
-#define EX(insn,reg,addr,handler)                      \
-9:     insn    reg, addr;                              \
-       .section __ex_table,"a";                        \
-       PTR     9b, handler;                            \
-       .previous
-
-       .macro  f_fill64 dst, offset, val, fixup
-       EX(LONG_S, \val, (\offset +  0 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  1 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  2 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  3 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  4 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  5 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  6 * LONGSIZE)(\dst), \fixup)
-       EX(LONG_S, \val, (\offset +  7 * LONGSIZE)(\dst), \fixup)
-       .endm
-
-/*
- * memset(void *s, int c, size_t n)
- *
- * a0: start of area to clear
- * a1: char to fill with
- * a2: size of area to clear
- */
-       .set    noreorder
-       .align  5
-LEAF(memset)
-       beqz            a1, 1f
-        move           v0, a0                  /* result */
-
-       andi            a1, 0xff                /* spread fillword */
-       dsll            t1, a1, 8
-       or              a1, t1
-       dsll            t1, a1, 16
-       or              a1, t1
-       dsll            t1, a1, 32
-       or              a1, t1
-1:
-
-FEXPORT(__bzero)
-       sltiu           t0, a2, LONGSIZE        /* very small region? */
-       bnez            t0, small_memset
-        andi           t0, a0, LONGMASK        /* aligned? */
-
-       beqz            t0, 1f
-        PTR_SUBU       t0, LONGSIZE            /* alignment in bytes */
-
-#ifdef __MIPSEB__
-       EX(sdl, a1, (a0), first_fixup)          /* make dword aligned */
-#endif
-#ifdef __MIPSEL__
-       EX(sdr, a1, (a0), first_fixup)          /* make dword aligned */
-#endif
-       PTR_SUBU        a0, t0                  /* long align ptr */
-       PTR_ADDU        a2, t0                  /* correct size */
-
-1:     ori             t1, a2, 0x3f            /* # of full blocks */
-       xori            t1, 0x3f
-       beqz            t1, memset_partial      /* no block to fill */
-        andi           t0, a2, 0x38
-
-       PTR_ADDU        t1, a0                  /* end address */
-       .set            reorder
-1:     PTR_ADDIU       a0, 64
-       f_fill64 a0, -64, a1, fwd_fixup
-       bne             t1, a0, 1b
-       .set            noreorder
-
-memset_partial:
-       PTR_LA          t1, 2f                  /* where to start */
-       .set            noat
-       dsrl            AT, t0, 1
-       PTR_SUBU        t1, AT
-       .set            noat
-       jr              t1
-        PTR_ADDU       a0, t0                  /* dest ptr */
-
-       .set            push
-       .set            noreorder
-       .set            nomacro
-       f_fill64 a0, -64, a1, partial_fixup     /* ... but first do longs ... */
-2:     .set            pop
-       andi            a2, LONGMASK            /* At most one long to go */
-
-       beqz            a2, 1f
-        PTR_ADDU       a0, a2                  /* What's left */
-#ifdef __MIPSEB__
-       EX(sdr, a1, -1(a0), last_fixup)
-#endif
-#ifdef __MIPSEL__
-       EX(sdl, a1, -1(a0), last_fixup)
-#endif
-1:     jr              ra
-        move           a2, zero
-
-small_memset:
-       beqz            a2, 2f
-        PTR_ADDU       t1, a0, a2
-
-1:     PTR_ADDIU       a0, 1                   /* fill bytewise */
-       bne             t1, a0, 1b
-        sb             a1, -1(a0)
-
-2:     jr              ra                      /* done */
-        move           a2, zero
-       END(memset)
-
-first_fixup:
-       jr      ra
-        nop
-
-fwd_fixup:
-       PTR_L           t0, TI_TASK($28)
-       LONG_L          t0, THREAD_BUADDR(t0)
-       andi            a2, 0x3f
-       LONG_ADDU       a2, t1
-       jr              ra
-        LONG_SUBU      a2, t0
-
-partial_fixup:
-       PTR_L           t0, TI_TASK($28)
-       LONG_L          t0, THREAD_BUADDR(t0)
-       andi            a2, LONGMASK
-       LONG_ADDU       a2, t1
-       jr              ra
-        LONG_SUBU      a2, t0
-
-last_fixup:
-       jr              ra
-        andi           v1, a2, LONGMASK
index 989c900..5ad501b 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for MIPS-specific library files..
 #
 
-lib-y  += csum_partial.o memcpy.o promlib.o \
+lib-y  += csum_partial.o memcpy.o memset.o promlib.o \
           strlen_user.o strncpy_user.o strnlen_user.o uncached.o
 
 obj-y  += iomap.o
diff --git a/arch/mips/lib/memset.S b/arch/mips/lib/memset.S
new file mode 100644 (file)
index 0000000..3f8b8b3
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * 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) 1998, 1999, 2000 by Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ */
+#include <asm/asm.h>
+#include <asm/asm-offsets.h>
+#include <asm/regdef.h>
+
+#if LONGSIZE == 4
+#define LONG_S_L swl
+#define LONG_S_R swr
+#else
+#define LONG_S_L sdl
+#define LONG_S_R sdr
+#endif
+
+#define EX(insn,reg,addr,handler)                      \
+9:     insn    reg, addr;                              \
+       .section __ex_table,"a";                        \
+       PTR     9b, handler;                            \
+       .previous
+
+       .macro  f_fill64 dst, offset, val, fixup
+       EX(LONG_S, \val, (\offset +  0 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset +  1 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset +  2 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset +  3 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset +  4 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset +  5 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset +  6 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset +  7 * LONGSIZE)(\dst), \fixup)
+#if LONGSIZE == 4
+       EX(LONG_S, \val, (\offset +  8 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset +  9 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset + 10 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset + 11 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset + 12 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset + 13 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset + 14 * LONGSIZE)(\dst), \fixup)
+       EX(LONG_S, \val, (\offset + 15 * LONGSIZE)(\dst), \fixup)
+#endif
+       .endm
+
+/*
+ * memset(void *s, int c, size_t n)
+ *
+ * a0: start of area to clear
+ * a1: char to fill with
+ * a2: size of area to clear
+ */
+       .set    noreorder
+       .align  5
+LEAF(memset)
+       beqz            a1, 1f
+        move           v0, a0                  /* result */
+
+       andi            a1, 0xff                /* spread fillword */
+       LONG_SLL                t1, a1, 8
+       or              a1, t1
+       LONG_SLL                t1, a1, 16
+#if LONGSIZE == 8
+       or              a1, t1
+       LONG_SLL                t1, a1, 32
+#endif
+       or              a1, t1
+1:
+
+FEXPORT(__bzero)
+       sltiu           t0, a2, LONGSIZE        /* very small region? */
+       bnez            t0, small_memset
+        andi           t0, a0, LONGMASK        /* aligned? */
+
+       beqz            t0, 1f
+        PTR_SUBU       t0, LONGSIZE            /* alignment in bytes */
+
+#ifdef __MIPSEB__
+       EX(LONG_S_L, a1, (a0), first_fixup)     /* make word/dword aligned */
+#endif
+#ifdef __MIPSEL__
+       EX(LONG_S_R, a1, (a0), first_fixup)     /* make word/dword aligned */
+#endif
+       PTR_SUBU        a0, t0                  /* long align ptr */
+       PTR_ADDU        a2, t0                  /* correct size */
+
+1:     ori             t1, a2, 0x3f            /* # of full blocks */
+       xori            t1, 0x3f
+       beqz            t1, memset_partial      /* no block to fill */
+        andi           t0, a2, 0x40-LONGSIZE
+
+       PTR_ADDU        t1, a0                  /* end address */
+       .set            reorder
+1:     PTR_ADDIU       a0, 64
+       f_fill64 a0, -64, a1, fwd_fixup
+       bne             t1, a0, 1b
+       .set            noreorder
+
+memset_partial:
+       PTR_LA          t1, 2f                  /* where to start */
+#if LONGSIZE == 4
+       PTR_SUBU        t1, t0
+#else
+       .set            noat
+       LONG_SRL                AT, t0, 1
+       PTR_SUBU        t1, AT
+       .set            noat
+#endif
+       jr              t1
+        PTR_ADDU       a0, t0                  /* dest ptr */
+
+       .set            push
+       .set            noreorder
+       .set            nomacro
+       f_fill64 a0, -64, a1, partial_fixup     /* ... but first do longs ... */
+2:     .set            pop
+       andi            a2, LONGMASK            /* At most one long to go */
+
+       beqz            a2, 1f
+        PTR_ADDU       a0, a2                  /* What's left */
+#ifdef __MIPSEB__
+       EX(LONG_S_R, a1, -1(a0), last_fixup)
+#endif
+#ifdef __MIPSEL__
+       EX(LONG_S_L, a1, -1(a0), last_fixup)
+#endif
+1:     jr              ra
+        move           a2, zero
+
+small_memset:
+       beqz            a2, 2f
+        PTR_ADDU       t1, a0, a2
+
+1:     PTR_ADDIU       a0, 1                   /* fill bytewise */
+       bne             t1, a0, 1b
+        sb             a1, -1(a0)
+
+2:     jr              ra                      /* done */
+        move           a2, zero
+       END(memset)
+
+first_fixup:
+       jr      ra
+        nop
+
+fwd_fixup:
+       PTR_L           t0, TI_TASK($28)
+       LONG_L          t0, THREAD_BUADDR(t0)
+       andi            a2, 0x3f
+       LONG_ADDU       a2, t1
+       jr              ra
+        LONG_SUBU      a2, t0
+
+partial_fixup:
+       PTR_L           t0, TI_TASK($28)
+       LONG_L          t0, THREAD_BUADDR(t0)
+       andi            a2, LONGMASK
+       LONG_ADDU       a2, t1
+       jr              ra
+        LONG_SUBU      a2, t0
+
+last_fixup:
+       jr              ra
+        andi           v1, a2, LONGMASK
index 98ce89f..2388f7f 100644 (file)
@@ -44,20 +44,24 @@ unsigned long __init run_uncached(void *func)
 
        if (sp >= (long)CKSEG0 && sp < (long)CKSEG2)
                usp = CKSEG1ADDR(sp);
+#ifdef CONFIG_64BIT
        else if ((long long)sp >= (long long)PHYS_TO_XKPHYS(0LL, 0) &&
                 (long long)sp < (long long)PHYS_TO_XKPHYS(8LL, 0))
                usp = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
                                     XKPHYS_TO_PHYS((long long)sp));
+#endif
        else {
                BUG();
                usp = sp;
        }
        if (lfunc >= (long)CKSEG0 && lfunc < (long)CKSEG2)
                ufunc = CKSEG1ADDR(lfunc);
+#ifdef CONFIG_64BIT
        else if ((long long)lfunc >= (long long)PHYS_TO_XKPHYS(0LL, 0) &&
                 (long long)lfunc < (long long)PHYS_TO_XKPHYS(8LL, 0))
                ufunc = PHYS_TO_XKPHYS((long long)K_CALG_UNCACHED,
                                       XKPHYS_TO_PHYS((long long)lfunc));
+#endif
        else {
                BUG();
                ufunc = lfunc;
index 43dba6c..dfa0acb 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/kernel.h>
 
 #include <asm/gdb-stub.h>
 #include <asm/io.h>
@@ -69,7 +70,7 @@ static void end_atlas_irq(unsigned int irq)
 }
 
 static struct irq_chip atlas_irq_type = {
-       .typename = "Atlas",
+       .name = "Atlas",
        .ack = disable_atlas_irq,
        .mask = disable_atlas_irq,
        .mask_ack = disable_atlas_irq,
@@ -220,7 +221,7 @@ msc_irqmap_t __initdata msc_irqmap[] = {
        {MSC01C_INT_TMR,                MSC01_IRQ_EDGE, 0},
        {MSC01C_INT_PCI,                MSC01_IRQ_LEVEL, 0},
 };
-int __initdata msc_nr_irqs = sizeof(msc_irqmap) / sizeof(*msc_irqmap);
+int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap);
 
 msc_irqmap_t __initdata msc_eicirqmap[] = {
        {MSC01E_INT_SW0,                MSC01_IRQ_LEVEL, 0},
@@ -231,14 +232,14 @@ msc_irqmap_t __initdata msc_eicirqmap[] = {
        {MSC01E_INT_PERFCTR,            MSC01_IRQ_LEVEL, 0},
        {MSC01E_INT_CPUCTR,             MSC01_IRQ_LEVEL, 0}
 };
-int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap) / sizeof(*msc_eicirqmap);
+int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
 
 void __init arch_init_irq(void)
 {
        init_atlas_irqs(ATLAS_INT_BASE);
 
        if (!cpu_has_veic)
-               mips_cpu_irq_init(MIPSCPU_INT_BASE);
+               mips_cpu_irq_init();
 
        switch(mips_revision_corid) {
        case MIPS_REVISION_CORID_CORE_MSC:
index eeed944..ebf0e16 100644 (file)
@@ -166,9 +166,8 @@ void __init prom_meminit(void)
        }
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       unsigned long freed = 0;
        unsigned long addr;
        int i;
 
@@ -176,17 +175,8 @@ unsigned long __init prom_free_prom_memory(void)
                if (boot_mem_map.map[i].type != BOOT_MEM_ROM_DATA)
                        continue;
 
-               addr = PAGE_ALIGN(boot_mem_map.map[i].addr);
-               while (addr < boot_mem_map.map[i].addr
-                             + boot_mem_map.map[i].size) {
-                       ClearPageReserved(virt_to_page(__va(addr)));
-                       init_page_count(virt_to_page(__va(addr)));
-                       free_page((unsigned long)__va(addr));
-                       addr += PAGE_SIZE;
-                       freed += PAGE_SIZE;
-               }
+               addr = boot_mem_map.map[i].addr;
+               free_init_pages("prom memory",
+                               addr, addr + boot_mem_map.map[i].size);
        }
-       printk("Freeing prom memory: %ldkb freed\n", freed >> 10);
-
-       return freed;
 }
index 90ad5bf..3c206bb 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
+#include <linux/kernel.h>
 #include <linux/random.h>
 
 #include <asm/i8259.h>
@@ -289,7 +290,7 @@ msc_irqmap_t __initdata msc_irqmap[] = {
        {MSC01C_INT_TMR,                MSC01_IRQ_EDGE, 0},
        {MSC01C_INT_PCI,                MSC01_IRQ_LEVEL, 0},
 };
-int __initdata msc_nr_irqs = sizeof(msc_irqmap)/sizeof(msc_irqmap_t);
+int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap);
 
 msc_irqmap_t __initdata msc_eicirqmap[] = {
        {MSC01E_INT_SW0,                MSC01_IRQ_LEVEL, 0},
@@ -303,14 +304,14 @@ msc_irqmap_t __initdata msc_eicirqmap[] = {
        {MSC01E_INT_PERFCTR,            MSC01_IRQ_LEVEL, 0},
        {MSC01E_INT_CPUCTR,             MSC01_IRQ_LEVEL, 0}
 };
-int __initdata msc_nr_eicirqs = sizeof(msc_eicirqmap)/sizeof(msc_irqmap_t);
+int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
 
 void __init arch_init_irq(void)
 {
        init_i8259_irqs();
 
        if (!cpu_has_veic)
-               mips_cpu_irq_init (MIPSCPU_INT_BASE);
+               mips_cpu_irq_init();
 
         switch(mips_revision_corid) {
         case MIPS_REVISION_CORID_CORE_MSC:
index 874ccb0..c4b9de3 100644 (file)
@@ -113,5 +113,5 @@ asmlinkage void plat_irq_dispatch(void)
 
 void __init arch_init_irq(void)
 {
-       mips_cpu_irq_init(MIPSCPU_INT_BASE);
+       mips_cpu_irq_init();
 }
index 2ce449d..15ac065 100644 (file)
@@ -21,9 +21,7 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <asm/mips-boards/simint.h>
-
-
-extern void mips_cpu_irq_init(int);
+#include <asm/irq_cpu.h>
 
 static inline int clz(unsigned long x)
 {
@@ -86,5 +84,5 @@ asmlinkage void plat_irq_dispatch(void)
 
 void __init arch_init_irq(void)
 {
-       mips_cpu_irq_init(MIPSCPU_INT_BASE);
+       mips_cpu_irq_init();
 }
index f7ce769..46bc16f 100644 (file)
@@ -99,10 +99,9 @@ void __init prom_meminit(void)
        }
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
        int i;
-       unsigned long freed = 0;
        unsigned long addr;
 
        for (i = 0; i < boot_mem_map.nr_map; i++) {
@@ -110,16 +109,7 @@ unsigned long __init prom_free_prom_memory(void)
                        continue;
 
                addr = boot_mem_map.map[i].addr;
-               while (addr < boot_mem_map.map[i].addr
-                             + boot_mem_map.map[i].size) {
-                       ClearPageReserved(virt_to_page(__va(addr)));
-                       init_page_count(virt_to_page(__va(addr)));
-                       free_page((unsigned long)__va(addr));
-                       addr += PAGE_SIZE;
-                       freed += PAGE_SIZE;
-               }
+               free_init_pages("prom memory",
+                               addr, addr + boot_mem_map.map[i].size);
        }
-       printk("Freeing prom memory: %ldkb freed\n", freed >> 10);
-
-       return freed;
 }
index 49065c1..125a4a8 100644 (file)
@@ -341,7 +341,6 @@ static int __init page_is_ram(unsigned long pagenr)
 void __init paging_init(void)
 {
        unsigned long zones_size[MAX_NR_ZONES] = { 0, };
-       unsigned long max_dma, low;
 #ifndef CONFIG_FLATMEM
        unsigned long zholes_size[MAX_NR_ZONES] = { 0, };
        unsigned long i, j, pfn;
@@ -354,19 +353,19 @@ void __init paging_init(void)
 #endif
        kmap_coherent_init();
 
-       max_dma = virt_to_phys((char *)MAX_DMA_ADDRESS) >> PAGE_SHIFT;
-       low = max_low_pfn;
-
 #ifdef CONFIG_ISA
-       if (low < max_dma)
-               zones_size[ZONE_DMA] = low;
-       else {
-               zones_size[ZONE_DMA] = max_dma;
-               zones_size[ZONE_NORMAL] = low - max_dma;
-       }
-#else
-       zones_size[ZONE_DMA] = low;
+       if (max_low_pfn >= MAX_DMA_PFN)
+               if (min_low_pfn >= MAX_DMA_PFN) {
+                       zones_size[ZONE_DMA] = 0;
+                       zones_size[ZONE_NORMAL] = max_low_pfn - min_low_pfn;
+               } else {
+                       zones_size[ZONE_DMA] = MAX_DMA_PFN - min_low_pfn;
+                       zones_size[ZONE_NORMAL] = max_low_pfn - MAX_DMA_PFN;
+               }
+       else
 #endif
+       zones_size[ZONE_DMA] = max_low_pfn - min_low_pfn;
+
 #ifdef CONFIG_HIGHMEM
        zones_size[ZONE_HIGHMEM] = highend_pfn - highstart_pfn;
 
@@ -467,7 +466,7 @@ void __init mem_init(void)
 }
 #endif /* !CONFIG_NEED_MULTIPLE_NODES */
 
-static void free_init_pages(char *what, unsigned long begin, unsigned long end)
+void free_init_pages(const char *what, unsigned long begin, unsigned long end)
 {
        unsigned long pfn;
 
@@ -493,18 +492,25 @@ void free_initrd_mem(unsigned long start, unsigned long end)
 }
 #endif
 
-extern unsigned long prom_free_prom_memory(void);
-
 void free_initmem(void)
 {
-       unsigned long freed;
-
-       freed = prom_free_prom_memory();
-       if (freed)
-               printk(KERN_INFO "Freeing firmware memory: %ldkb freed\n",
-                      freed >> 10);
-
+       prom_free_prom_memory();
        free_init_pages("unused kernel memory",
                        __pa_symbol(&__init_begin),
                        __pa_symbol(&__init_end));
 }
+
+unsigned long pgd_current[NR_CPUS];
+/*
+ * On 64-bit we've got three-level pagetables with a slightly
+ * different layout ...
+ */
+#define __page_aligned(order) __attribute__((__aligned__(PAGE_SIZE<<order)))
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned(PGD_ORDER);
+#ifdef CONFIG_64BIT
+#ifdef MODULE_START
+pgd_t module_pg_dir[PTRS_PER_PGD] __page_aligned(PGD_ORDER);
+#endif
+pmd_t invalid_pmd_table[PTRS_PER_PMD] __page_aligned(PMD_ORDER);
+#endif
+pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned(PTE_ORDER);
index 67372f3..2e8cebd 100644 (file)
@@ -6,7 +6,7 @@
 # unless it's something special (ie not a .c file).
 #
 
-obj-y += irq.o prom.o reset.o setup.o
+obj-y += irq.o platform.o prom.o reset.o setup.o
 
 obj-$(CONFIG_SERIAL_8250_CONSOLE) += ja-console.o
 obj-$(CONFIG_REMOTE_DEBUG) += dbg_io.o
index 2efb25a..f2b4325 100644 (file)
@@ -82,8 +82,8 @@ void __init arch_init_irq(void)
         */
        clear_c0_status(ST0_IM);
 
-       mips_cpu_irq_init(0);
-       rm7k_cpu_irq_init(8);
+       mips_cpu_irq_init();
+       rm7k_cpu_irq_init();
 
        /* set up the cascading interrupts */
        setup_irq(8, &cascade_mv64340);
index 6978654..022f697 100644 (file)
@@ -46,7 +46,9 @@
 
 extern unsigned long ja_fpga_base;
 
-#define JAGUAR_FPGA_WRITE(x,y) writeb(x, ja_fpga_base + JAGUAR_ATX_REG_##y)
-#define JAGUAR_FPGA_READ(x) readb(ja_fpga_base + JAGUAR_ATX_REG_##x)
+#define __FPGA_REG_TO_ADDR(reg)                                                \
+       ((void *) ja_fpga_base + JAGUAR_ATX_REG_##reg)
+#define JAGUAR_FPGA_WRITE(x, reg) writeb(x, __FPGA_REG_TO_ADDR(reg))
+#define JAGUAR_FPGA_READ(reg) readb(__FPGA_REG_TO_ADDR(reg))
 
 #endif
diff --git a/arch/mips/momentum/jaguar_atx/platform.c b/arch/mips/momentum/jaguar_atx/platform.c
new file mode 100644 (file)
index 0000000..035ea51
--- /dev/null
@@ -0,0 +1,235 @@
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+#include <linux/ioport.h>
+#include <linux/mv643xx.h>
+#include <linux/platform_device.h>
+
+#include "jaguar_atx_fpga.h"
+
+#if defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE)
+
+static struct resource mv643xx_eth_shared_resources[] = {
+       [0] = {
+               .name   = "ethernet shared base",
+               .start  = 0xf1000000 + MV643XX_ETH_SHARED_REGS,
+               .end    = 0xf1000000 + MV643XX_ETH_SHARED_REGS +
+                                      MV643XX_ETH_SHARED_REGS_SIZE - 1,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device mv643xx_eth_shared_device = {
+       .name           = MV643XX_ETH_SHARED_NAME,
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(mv643xx_eth_shared_resources),
+       .resource       = mv643xx_eth_shared_resources,
+};
+
+#define MV_SRAM_BASE                   0xfe000000UL
+#define MV_SRAM_SIZE                   (256 * 1024)
+
+#define MV_SRAM_RXRING_SIZE            (MV_SRAM_SIZE / 4)
+#define MV_SRAM_TXRING_SIZE            (MV_SRAM_SIZE / 4)
+
+#define MV_SRAM_BASE_ETH0              MV_SRAM_BASE
+#define MV_SRAM_BASE_ETH1              (MV_SRAM_BASE + (MV_SRAM_SIZE / 2))
+
+#define MV64x60_IRQ_ETH_0 48
+#define MV64x60_IRQ_ETH_1 49
+#define MV64x60_IRQ_ETH_2 50
+
+#ifdef CONFIG_MV643XX_ETH_0
+
+static struct resource mv64x60_eth0_resources[] = {
+       [0] = {
+               .name   = "eth0 irq",
+               .start  = MV64x60_IRQ_ETH_0,
+               .end    = MV64x60_IRQ_ETH_0,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static char eth0_mac_addr[ETH_ALEN];
+
+static struct mv643xx_eth_platform_data eth0_pd = {
+       .mac_addr       = eth0_mac_addr,
+
+       .tx_sram_addr   = MV_SRAM_BASE_ETH0,
+       .tx_sram_size   = MV_SRAM_TXRING_SIZE,
+       .tx_queue_size  = MV_SRAM_TXRING_SIZE / 16,
+
+       .rx_sram_addr   = MV_SRAM_BASE_ETH0 + MV_SRAM_TXRING_SIZE,
+       .rx_sram_size   = MV_SRAM_RXRING_SIZE,
+       .rx_queue_size  = MV_SRAM_RXRING_SIZE / 16,
+};
+
+static struct platform_device eth0_device = {
+       .name           = MV643XX_ETH_NAME,
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(mv64x60_eth0_resources),
+       .resource       = mv64x60_eth0_resources,
+       .dev = {
+               .platform_data = &eth0_pd,
+       },
+};
+#endif /* CONFIG_MV643XX_ETH_0 */
+
+#ifdef CONFIG_MV643XX_ETH_1
+
+static struct resource mv64x60_eth1_resources[] = {
+       [0] = {
+               .name   = "eth1 irq",
+               .start  = MV64x60_IRQ_ETH_1,
+               .end    = MV64x60_IRQ_ETH_1,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static char eth1_mac_addr[ETH_ALEN];
+
+static struct mv643xx_eth_platform_data eth1_pd = {
+       .mac_addr       = eth1_mac_addr,
+
+       .tx_sram_addr   = MV_SRAM_BASE_ETH1,
+       .tx_sram_size   = MV_SRAM_TXRING_SIZE,
+       .tx_queue_size  = MV_SRAM_TXRING_SIZE / 16,
+
+       .rx_sram_addr   = MV_SRAM_BASE_ETH1 + MV_SRAM_TXRING_SIZE,
+       .rx_sram_size   = MV_SRAM_RXRING_SIZE,
+       .rx_queue_size  = MV_SRAM_RXRING_SIZE / 16,
+};
+
+static struct platform_device eth1_device = {
+       .name           = MV643XX_ETH_NAME,
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(mv64x60_eth1_resources),
+       .resource       = mv64x60_eth1_resources,
+       .dev = {
+               .platform_data = &eth1_pd,
+       },
+};
+#endif /* CONFIG_MV643XX_ETH_1 */
+
+#ifdef CONFIG_MV643XX_ETH_2
+
+static struct resource mv64x60_eth2_resources[] = {
+       [0] = {
+               .name   = "eth2 irq",
+               .start  = MV64x60_IRQ_ETH_2,
+               .end    = MV64x60_IRQ_ETH_2,
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static char eth2_mac_addr[ETH_ALEN];
+
+static struct mv643xx_eth_platform_data eth2_pd = {
+       .mac_addr       = eth2_mac_addr,
+};
+
+static struct platform_device eth2_device = {
+       .name           = MV643XX_ETH_NAME,
+       .id             = 1,
+       .num_resources  = ARRAY_SIZE(mv64x60_eth2_resources),
+       .resource       = mv64x60_eth2_resources,
+       .dev = {
+               .platform_data = &eth2_pd,
+       },
+};
+#endif /* CONFIG_MV643XX_ETH_2 */
+
+static struct platform_device *mv643xx_eth_pd_devs[] __initdata = {
+       &mv643xx_eth_shared_device,
+#ifdef CONFIG_MV643XX_ETH_0
+       &eth0_device,
+#endif
+#ifdef CONFIG_MV643XX_ETH_1
+       &eth1_device,
+#endif
+#ifdef CONFIG_MV643XX_ETH_2
+       &eth2_device,
+#endif
+};
+
+static u8 __init exchange_bit(u8 val, u8 cs)
+{
+       /* place the data */
+       JAGUAR_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
+       udelay(1);
+
+       /* turn the clock on */
+       JAGUAR_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
+       udelay(1);
+
+       /* turn the clock off and read-strobe */
+       JAGUAR_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
+
+       /* return the data */
+       return (JAGUAR_FPGA_READ(EEPROM_MODE) >> 3) & 0x1;
+}
+
+static void __init get_mac(char dest[6])
+{
+       u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+       int i,j;
+
+       for (i = 0; i < 12; i++)
+               exchange_bit(read_opcode[i], 1);
+
+       for (j = 0; j < 6; j++) {
+               dest[j] = 0;
+               for (i = 0; i < 8; i++) {
+                       dest[j] <<= 1;
+                       dest[j] |= exchange_bit(0, 1);
+               }
+       }
+
+       /* turn off CS */
+       exchange_bit(0,0);
+}
+
+/*
+ * Copy and increment ethernet MAC address by a small value.
+ *
+ * This is useful for systems where the only one MAC address is stored in
+ * non-volatile memory for multiple ports.
+ */
+static inline void eth_mac_add(unsigned char *dst, unsigned char *src,
+       unsigned int add)
+{
+       int i;
+
+       BUG_ON(add >= 256);
+
+       for (i = ETH_ALEN; i >= 0; i--) {
+               dst[i] = src[i] + add;
+               add = dst[i] < src[i];          /* compute carry */
+       }
+
+       WARN_ON(add);
+}
+
+static int __init mv643xx_eth_add_pds(void)
+{
+       unsigned char mac[ETH_ALEN];
+       int ret;
+
+       get_mac(mac);
+#ifdef CONFIG_MV643XX_ETH_0
+       eth_mac_add(eth1_mac_addr, mac, 0);
+#endif
+#ifdef CONFIG_MV643XX_ETH_1
+       eth_mac_add(eth1_mac_addr, mac, 1);
+#endif
+#ifdef CONFIG_MV643XX_ETH_2
+       eth_mac_add(eth2_mac_addr, mac, 2);
+#endif
+       ret = platform_add_devices(mv643xx_eth_pd_devs,
+                       ARRAY_SIZE(mv643xx_eth_pd_devs));
+
+       return ret;
+}
+
+device_initcall(mv643xx_eth_add_pds);
+
+#endif /* defined(CONFIG_MV643XX_ETH) || defined(CONFIG_MV643XX_ETH_MODULE) */
index 3d27129..5dd154e 100644 (file)
@@ -39,56 +39,6 @@ const char *get_system_type(void)
        return "Momentum Jaguar-ATX";
 }
 
-#ifdef CONFIG_MV643XX_ETH
-extern unsigned char prom_mac_addr_base[6];
-
-static void burn_clocks(void)
-{
-       int i;
-
-       /* this loop should burn at least 1us -- this should be plenty */
-       for (i = 0; i < 0x10000; i++)
-               ;
-}
-
-static u8 exchange_bit(u8 val, u8 cs)
-{
-       /* place the data */
-       JAGUAR_FPGA_WRITE((val << 2) | cs, EEPROM_MODE);
-       burn_clocks();
-
-       /* turn the clock on */
-       JAGUAR_FPGA_WRITE((val << 2) | cs | 0x2, EEPROM_MODE);
-       burn_clocks();
-
-       /* turn the clock off and read-strobe */
-       JAGUAR_FPGA_WRITE((val << 2) | cs | 0x10, EEPROM_MODE);
-
-       /* return the data */
-       return ((JAGUAR_FPGA_READ(EEPROM_MODE) >> 3) & 0x1);
-}
-
-void get_mac(char dest[6])
-{
-       u8 read_opcode[12] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-       int i,j;
-
-       for (i = 0; i < 12; i++)
-               exchange_bit(read_opcode[i], 1);
-
-       for (j = 0; j < 6; j++) {
-               dest[j] = 0;
-               for (i = 0; i < 8; i++) {
-                       dest[j] <<= 1;
-                       dest[j] |= exchange_bit(0, 1);
-               }
-       }
-
-       /* turn off CS */
-       exchange_bit(0,0);
-}
-#endif
-
 #ifdef CONFIG_64BIT
 
 unsigned long signext(unsigned long addr)
@@ -228,16 +178,10 @@ void __init prom_init(void)
 #endif /* CONFIG_64BIT */
        mips_machgroup = MACH_GROUP_MOMENCO;
        mips_machtype = MACH_MOMENCO_JAGUAR_ATX;
-
-#ifdef CONFIG_MV643XX_ETH
-       /* get the base MAC address for on-board ethernet ports */
-       get_mac(prom_mac_addr_base);
-#endif
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
 
 void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
index cea0e5d..3862d1d 100644 (file)
@@ -65,7 +65,7 @@ void __init arch_init_irq(void)
         */
        clear_c0_status(ST0_IM | ST0_BEV);
 
-       rm7k_cpu_irq_init(8);
+       rm7k_cpu_irq_init();
 
        /* set up the cascading interrupts */
        setup_irq(8, &cascade_mv64340);         /* unmask intControl IM8, IRQ 9 */
index 6ce9b7f..8e02df6 100644 (file)
@@ -180,9 +180,8 @@ void __init prom_init(void)
 #endif
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
 
 void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
index bb11fef..186a140 100644 (file)
@@ -84,7 +84,7 @@ void ll_cpci_irq(void)
 }
 
 struct irq_chip cpci_irq_type = {
-       .typename = "CPCI/FPGA",
+       .name = "CPCI/FPGA",
        .ack = mask_cpci_irq,
        .mask = mask_cpci_irq,
        .mask_ack = mask_cpci_irq,
index 2128684..32d6fb4 100644 (file)
@@ -1,6 +1,4 @@
 
-#ifdef CONFIG_KGDB
-
 #include <asm/serial.h> /* For the serial port location and base baud */
 
 /* --- CONFIG --- */
@@ -121,5 +119,3 @@ int putDebugChar(uint8 byte)
        UART16550_WRITE(OFS_SEND_BUFFER, byte);
        return 1;
 }
-
-#endif
index ea65223..40472f7 100644 (file)
@@ -94,7 +94,7 @@ void __init arch_init_irq(void)
         */
        clear_c0_status(ST0_IM);
 
-       mips_cpu_irq_init(0);
+       mips_cpu_irq_init();
 
        /* set up the cascading interrupts */
        setup_irq(3, &cascade_fpga);
index d0b77e1..b689cee 100644 (file)
@@ -178,7 +178,6 @@ void __init prom_init(void)
 #endif
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
index a7a80c0..de1a31e 100644 (file)
@@ -77,7 +77,7 @@ void ll_uart_irq(void)
 }
 
 struct irq_chip uart_irq_type = {
-       .typename = "UART/FPGA",
+       .name = "UART/FPGA",
        .ack = mask_uart_irq,
        .mask = mask_uart_irq,
        .mask_ack = mask_uart_irq,
index 2128684..32d6fb4 100644 (file)
@@ -1,6 +1,4 @@
 
-#ifdef CONFIG_KGDB
-
 #include <asm/serial.h> /* For the serial port location and base baud */
 
 /* --- CONFIG --- */
@@ -121,5 +119,3 @@ int putDebugChar(uint8 byte)
        UART16550_WRITE(OFS_SEND_BUFFER, byte);
        return 1;
 }
-
-#endif
index da46524..273541f 100644 (file)
@@ -94,8 +94,8 @@ void __init arch_init_irq(void)
        clear_c0_status(ST0_IM);
        local_irq_disable();
 
-       mips_cpu_irq_init(0);
-       rm7k_cpu_irq_init(8);
+       mips_cpu_irq_init();
+       rm7k_cpu_irq_init();
 
        gt64240_irq_init();
 }
index 2f75c6b..836d083 100644 (file)
@@ -79,7 +79,6 @@ void __init prom_init(void)
        }
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
index 55feaf7..ca395ef 100644 (file)
@@ -11,7 +11,7 @@ config PROFILING
 
 config OPROFILE
        tristate "OProfile system profiling (EXPERIMENTAL)"
-       depends on PROFILING && EXPERIMENTAL
+       depends on PROFILING && !!MIPS_MT_SMTC && EXPERIMENTAL
        help
          OProfile is a profiling system capable of profiling the
          whole system, include the kernel, kernel modules, libraries,
index 597b897..a8d9d22 100644 (file)
  */
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/kernel.h>
 
 #include <asm/io.h>
+#include <asm/i8259.h>
 #include <asm/vr41xx/cmbvr4133.h>
 
 extern int vr4133_rockhopper;
@@ -142,7 +144,7 @@ int rockhopper_get_irq(struct pci_dev *dev, u8 pin, u8 slot)
        if (bus == NULL)
                return -1;
 
-       for (i = 0; i < sizeof (int_map) / sizeof (int_map[0]); i++) {
+       for (i = 0; i < ARRAY_SIZE(int_map); i++) {
                if (int_map[i].bus == bus->number && int_map[i].slot == slot) {
                        int line;
                        for (line = 0; line < 4; line++)
@@ -160,17 +162,7 @@ int rockhopper_get_irq(struct pci_dev *dev, u8 pin, u8 slot)
 #ifdef CONFIG_ROCKHOPPER
 void i8259_init(void)
 {
-       outb(0x11, 0x20);               /* Master ICW1 */
-       outb(I8259_IRQ_BASE, 0x21);     /* Master ICW2 */
-       outb(0x04, 0x21);               /* Master ICW3 */
-       outb(0x01, 0x21);               /* Master ICW4 */
-       outb(0xff, 0x21);               /* Master IMW */
-
-       outb(0x11, 0xa0);               /* Slave ICW1 */
-       outb(I8259_IRQ_BASE + 8, 0xa1); /* Slave ICW2 */
-       outb(0x02, 0xa1);               /* Slave ICW3 */
-       outb(0x01, 0xa1);               /* Slave ICW4 */
-       outb(0xff, 0xa1);               /* Slave IMW */
+       init_i8259_irqs();
 
        outb(0x00, 0x4d0);
        outb(0x02, 0x4d1);      /* USB IRQ9 is level */
index 2c36c10..d48665e 100644 (file)
@@ -159,7 +159,7 @@ int pnx8550_set_gic_priority(int irq, int priority)
 }
 
 static struct irq_chip level_irq_type = {
-       .typename =     "PNX Level IRQ",
+       .name =         "PNX Level IRQ",
        .ack =          mask_irq,
        .mask =         mask_irq,
        .mask_ack =     mask_irq,
index eb6ec11..8aeed6c 100644 (file)
@@ -106,9 +106,8 @@ int get_ethernet_addr(char *ethernet_addr)
        return 0;
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
 
 extern int pnx8550_console_port;
index 0f659c9..6362c70 100644 (file)
@@ -93,7 +93,7 @@
  * Functions to READ and WRITE to serial port 1
  */
 #define        SERIAL_READ_1(ofs)              (*((volatile unsigned char*)    \
-                                       (TITAN_SERIAL_BASE_1 + ofs)
+                                       (TITAN_SERIAL_BASE_1 + ofs)))
 
 #define        SERIAL_WRITE_1(ofs, val)        ((*((volatile unsigned char*)   \
                                        (TITAN_SERIAL_BASE_1 + ofs))) = val)
index adb0485..428d1f4 100644 (file)
@@ -148,9 +148,9 @@ void __init arch_init_irq(void)
 {
        clear_c0_status(ST0_IM);
 
-       mips_cpu_irq_init(0);
-       rm7k_cpu_irq_init(8);
-       rm9k_cpu_irq_init(12);
+       mips_cpu_irq_init();
+       rm7k_cpu_irq_init();
+       rm9k_cpu_irq_init();
 
 #ifdef CONFIG_KGDB
        /* At this point, initialize the second serial port */
index 9fe4973..1e1685e 100644 (file)
@@ -132,9 +132,8 @@ void __init prom_init(void)
        prom_grab_secondary();
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
 
 void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
index 1b9b0d3..6a6e15e 100644 (file)
@@ -171,6 +171,7 @@ static void __init py_map_ocd(void)
 
 static void __init py_uart_setup(void)
 {
+#ifdef CONFIG_SERIAL_8250
        struct uart_port up;
 
        /*
@@ -188,6 +189,7 @@ static void __init py_uart_setup(void)
 
        if (early_serial_setup(&up))
                printk(KERN_ERR "Early serial init of port 0 failed\n");
+#endif /* CONFIG_SERIAL_8250 */
 }
 
 static void __init py_rtc_setup(void)
index d174fac..dae39b5 100644 (file)
@@ -1,6 +1,5 @@
 #include <linux/init.h>
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0UL;
 }
index a1a9af6..6b6e97b 100644 (file)
@@ -139,7 +139,7 @@ static void end_eisa1_irq(unsigned int irq)
 }
 
 static struct irq_chip ip22_eisa1_irq_type = {
-       .typename       = "IP22 EISA",
+       .name           = "IP22 EISA",
        .startup        = startup_eisa1_irq,
        .ack            = mask_and_ack_eisa1_irq,
        .mask           = disable_eisa1_irq,
@@ -194,7 +194,7 @@ static void end_eisa2_irq(unsigned int irq)
 }
 
 static struct irq_chip ip22_eisa2_irq_type = {
-       .typename       = "IP22 EISA",
+       .name           = "IP22 EISA",
        .startup        = startup_eisa2_irq,
        .ack            = mask_and_ack_eisa2_irq,
        .mask           = disable_eisa2_irq,
index c44f8be..b454924 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <asm/mipsregs.h>
 #include <asm/addrspace.h>
+#include <asm/irq_cpu.h>
 
 #include <asm/sgi/ioc.h>
 #include <asm/sgi/hpc3.h>
@@ -52,7 +53,7 @@ static void disable_local0_irq(unsigned int irq)
 }
 
 static struct irq_chip ip22_local0_irq_type = {
-       .typename       = "IP22 local 0",
+       .name           = "IP22 local 0",
        .ack            = disable_local0_irq,
        .mask           = disable_local0_irq,
        .mask_ack       = disable_local0_irq,
@@ -73,7 +74,7 @@ void disable_local1_irq(unsigned int irq)
 }
 
 static struct irq_chip ip22_local1_irq_type = {
-       .typename       = "IP22 local 1",
+       .name           = "IP22 local 1",
        .ack            = disable_local1_irq,
        .mask           = disable_local1_irq,
        .mask_ack       = disable_local1_irq,
@@ -94,7 +95,7 @@ void disable_local2_irq(unsigned int irq)
 }
 
 static struct irq_chip ip22_local2_irq_type = {
-       .typename       = "IP22 local 2",
+       .name           = "IP22 local 2",
        .ack            = disable_local2_irq,
        .mask           = disable_local2_irq,
        .mask_ack       = disable_local2_irq,
@@ -115,7 +116,7 @@ void disable_local3_irq(unsigned int irq)
 }
 
 static struct irq_chip ip22_local3_irq_type = {
-       .typename       = "IP22 local 3",
+       .name           = "IP22 local 3",
        .ack            = disable_local3_irq,
        .mask           = disable_local3_irq,
        .mask_ack       = disable_local3_irq,
@@ -253,8 +254,6 @@ asmlinkage void plat_irq_dispatch(void)
                indy_8254timer_irq();
 }
 
-extern void mips_cpu_irq_init(unsigned int irq_base);
-
 void __init arch_init_irq(void)
 {
        int i;
@@ -316,7 +315,7 @@ void __init arch_init_irq(void)
        sgint->cmeimask1 = 0;
 
        /* init CPU irqs */
-       mips_cpu_irq_init(SGINT_CPU);
+       mips_cpu_irq_init();
 
        for (i = SGINT_LOCAL0; i < SGI_INTERRUPTS; i++) {
                struct irq_chip *handler;
index b58bd52..ddb6506 100644 (file)
@@ -202,7 +202,6 @@ void __init sgimc_init(void)
 }
 
 void __init prom_meminit(void) {}
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
index 319f880..60ade76 100644 (file)
@@ -333,7 +333,7 @@ static inline void disable_bridge_irq(unsigned int irq)
 }
 
 static struct irq_chip bridge_irq_type = {
-       .typename       = "bridge",
+       .name           = "bridge",
        .startup        = startup_bridge_irq,
        .shutdown       = shutdown_bridge_irq,
        .ack            = disable_bridge_irq,
index 16e5682..0e3d535 100644 (file)
@@ -498,10 +498,9 @@ void __init prom_meminit(void)
        }
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
        /* We got nothing to free here ...  */
-       return 0;
 }
 
 extern void pagetable_init(void);
index c20e989..9ce5136 100644 (file)
@@ -181,7 +181,7 @@ static void disable_rt_irq(unsigned int irq)
 }
 
 static struct irq_chip rt_irq_type = {
-       .typename       = "SN HUB RT timer",
+       .name           = "SN HUB RT timer",
        .ack            = disable_rt_irq,
        .mask           = disable_rt_irq,
        .mask_ack       = disable_rt_irq,
index ae06386..8c450d9 100644 (file)
@@ -144,7 +144,7 @@ static void end_cpu_irq(unsigned int irq)
 }
 
 static struct irq_chip ip32_cpu_interrupt = {
-       .typename = "IP32 CPU",
+       .name = "IP32 CPU",
        .ack = disable_cpu_irq,
        .mask = disable_cpu_irq,
        .mask_ack = disable_cpu_irq,
@@ -193,7 +193,7 @@ static void end_crime_irq(unsigned int irq)
 }
 
 static struct irq_chip ip32_crime_interrupt = {
-       .typename = "IP32 CRIME",
+       .name = "IP32 CRIME",
        .ack = mask_and_ack_crime_irq,
        .mask = disable_crime_irq,
        .mask_ack = mask_and_ack_crime_irq,
@@ -234,7 +234,7 @@ static void end_macepci_irq(unsigned int irq)
 }
 
 static struct irq_chip ip32_macepci_interrupt = {
-       .typename = "IP32 MACE PCI",
+       .name = "IP32 MACE PCI",
        .ack = disable_macepci_irq,
        .mask = disable_macepci_irq,
        .mask_ack = disable_macepci_irq,
@@ -347,7 +347,7 @@ static void end_maceisa_irq(unsigned irq)
 }
 
 static struct irq_chip ip32_maceisa_interrupt = {
-       .typename = "IP32 MACE ISA",
+       .name = "IP32 MACE ISA",
        .ack = mask_and_ack_maceisa_irq,
        .mask = disable_maceisa_irq,
        .mask_ack = mask_and_ack_maceisa_irq,
@@ -379,7 +379,7 @@ static void end_mace_irq(unsigned int irq)
 }
 
 static struct irq_chip ip32_mace_interrupt = {
-       .typename = "IP32 MACE",
+       .name = "IP32 MACE",
        .ack = disable_mace_irq,
        .mask = disable_mace_irq,
        .mask_ack = disable_mace_irq,
index d37d40a..849d392 100644 (file)
@@ -43,7 +43,6 @@ void __init prom_meminit (void)
 }
 
 
-unsigned long __init prom_free_prom_memory (void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
index 2e8f6b2..1dc5d05 100644 (file)
@@ -82,7 +82,7 @@ extern char sb1250_duart_present[];
 #endif
 
 static struct irq_chip bcm1480_irq_type = {
-       .typename = "BCM1480-IMR",
+       .name = "BCM1480-IMR",
        .ack = ack_bcm1480_irq,
        .mask = disable_bcm1480_irq,
        .mask_ack = ack_bcm1480_irq,
index 6e8952d..9e6099e 100644 (file)
@@ -343,10 +343,9 @@ void __init prom_init(void)
        prom_meminit();
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
        /* Not sure what I'm supposed to do here.  Nothing, I think */
-       return 0;
 }
 
 void prom_putchar(char c)
index 82ce753..1482394 100644 (file)
@@ -67,7 +67,7 @@ extern char sb1250_duart_present[];
 #endif
 
 static struct irq_chip sb1250_irq_type = {
-       .typename = "SB1250-IMR",
+       .name = "SB1250-IMR",
        .ack = ack_sb1250_irq,
        .mask = disable_sb1250_irq,
        .mask_ack = ack_sb1250_irq,
index 3c33a45..257c4e6 100644 (file)
@@ -87,10 +87,9 @@ void __init prom_init(void)
        prom_meminit();
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
        /* Not sure what I'm supposed to do here.  Nothing, I think */
-       return 0;
 }
 
 void prom_putchar(char c)
index 8511bcc..039e8e5 100644 (file)
@@ -37,7 +37,7 @@ static void end_pciasic_irq(unsigned int irq)
 }
 
 static struct irq_chip pciasic_irq_type = {
-       .typename = "ASIC-PCI",
+       .name = "ASIC-PCI",
        .ack = disable_pciasic_irq,
        .mask = disable_pciasic_irq,
        .mask_ack = disable_pciasic_irq,
index d1d0f1f..1213d16 100644 (file)
@@ -67,9 +67,8 @@ void prom_printf(char *fmt, ...)
        va_end(args);
 }
 
-unsigned long prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
 
 /*
index ed4a19a..e7f3e5b 100644 (file)
@@ -120,7 +120,7 @@ static void tx4927_irq_pic_disable(unsigned int irq);
 
 #define TX4927_CP0_NAME "TX4927-CP0"
 static struct irq_chip tx4927_irq_cp0_type = {
-       .typename       = TX4927_CP0_NAME,
+       .name           = TX4927_CP0_NAME,
        .ack            = tx4927_irq_cp0_disable,
        .mask           = tx4927_irq_cp0_disable,
        .mask_ack       = tx4927_irq_cp0_disable,
@@ -129,7 +129,7 @@ static struct irq_chip tx4927_irq_cp0_type = {
 
 #define TX4927_PIC_NAME "TX4927-PIC"
 static struct irq_chip tx4927_irq_pic_type = {
-       .typename       = TX4927_PIC_NAME,
+       .name           = TX4927_PIC_NAME,
        .ack            = tx4927_irq_pic_disable,
        .mask           = tx4927_irq_pic_disable,
        .mask_ack       = tx4927_irq_pic_disable,
index b54b529..dcce88f 100644 (file)
@@ -228,7 +228,7 @@ static void toshiba_rbtx4927_irq_isa_mask_and_ack(unsigned int irq);
 
 #define TOSHIBA_RBTX4927_IOC_NAME "RBTX4927-IOC"
 static struct irq_chip toshiba_rbtx4927_irq_ioc_type = {
-       .typename = TOSHIBA_RBTX4927_IOC_NAME,
+       .name = TOSHIBA_RBTX4927_IOC_NAME,
        .ack = toshiba_rbtx4927_irq_ioc_disable,
        .mask = toshiba_rbtx4927_irq_ioc_disable,
        .mask_ack = toshiba_rbtx4927_irq_ioc_disable,
@@ -241,7 +241,7 @@ static struct irq_chip toshiba_rbtx4927_irq_ioc_type = {
 #ifdef CONFIG_TOSHIBA_FPCIB0
 #define TOSHIBA_RBTX4927_ISA_NAME "RBTX4927-ISA"
 static struct irq_chip toshiba_rbtx4927_irq_isa_type = {
-       .typename = TOSHIBA_RBTX4927_ISA_NAME,
+       .name = TOSHIBA_RBTX4927_ISA_NAME,
        .ack = toshiba_rbtx4927_irq_isa_mask_and_ack,
        .mask = toshiba_rbtx4927_irq_isa_disable,
        .mask_ack = toshiba_rbtx4927_irq_isa_mask_and_ack,
@@ -490,13 +490,13 @@ void toshiba_rbtx4927_irq_dump(char *key)
        {
                u32 i, j = 0;
                for (i = 0; i < NR_IRQS; i++) {
-                       if (strcmp(irq_desc[i].chip->typename, "none")
+                       if (strcmp(irq_desc[i].chip->name, "none")
                            == 0)
                                continue;
 
                        if ((i >= 1)
-                           && (irq_desc[i - 1].chip->typename ==
-                               irq_desc[i].chip->typename)) {
+                           && (irq_desc[i - 1].chip->name ==
+                               irq_desc[i].chip->name)) {
                                j++;
                        } else {
                                j = 0;
@@ -510,7 +510,7 @@ void toshiba_rbtx4927_irq_dump(char *key)
                             (u32) (irq_desc[i].action ? irq_desc[i].
                                    action->handler : 0),
                             irq_desc[i].depth,
-                            irq_desc[i].chip->typename, j);
+                            irq_desc[i].chip->name, j);
                }
        }
 #endif
index efe5056..9a3a5ba 100644 (file)
@@ -80,9 +80,8 @@ void __init prom_init(void)
        add_memory_region(0, msize << 20, BOOT_MEM_RAM);
 }
 
-unsigned long __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
 
 const char *get_system_type(void)
index a347b42..3a2dbfc 100644 (file)
@@ -49,7 +49,7 @@ static void tx4938_irq_pic_disable(unsigned int irq);
 
 #define TX4938_CP0_NAME "TX4938-CP0"
 static struct irq_chip tx4938_irq_cp0_type = {
-       .typename = TX4938_CP0_NAME,
+       .name = TX4938_CP0_NAME,
        .ack = tx4938_irq_cp0_disable,
        .mask = tx4938_irq_cp0_disable,
        .mask_ack = tx4938_irq_cp0_disable,
@@ -58,7 +58,7 @@ static struct irq_chip tx4938_irq_cp0_type = {
 
 #define TX4938_PIC_NAME "TX4938-PIC"
 static struct irq_chip tx4938_irq_pic_type = {
-       .typename = TX4938_PIC_NAME,
+       .name = TX4938_PIC_NAME,
        .ack = tx4938_irq_pic_disable,
        .mask = tx4938_irq_pic_disable,
        .mask_ack = tx4938_irq_pic_disable,
index b6f363d..2e96dbb 100644 (file)
@@ -92,7 +92,7 @@ static void toshiba_rbtx4938_irq_ioc_disable(unsigned int irq);
 
 #define TOSHIBA_RBTX4938_IOC_NAME "RBTX4938-IOC"
 static struct irq_chip toshiba_rbtx4938_irq_ioc_type = {
-       .typename = TOSHIBA_RBTX4938_IOC_NAME,
+       .name = TOSHIBA_RBTX4938_IOC_NAME,
        .ack = toshiba_rbtx4938_irq_ioc_disable,
        .mask = toshiba_rbtx4938_irq_ioc_disable,
        .mask_ack = toshiba_rbtx4938_irq_ioc_disable,
index e44daf3..7dc6a0a 100644 (file)
@@ -56,9 +56,8 @@ void __init prom_init(void)
        return;
 }
 
-unsigned long  __init prom_free_prom_memory(void)
+void __init prom_free_prom_memory(void)
 {
-       return 0;
 }
 
 void __init prom_fixup_mem_map(unsigned long start, unsigned long end)
index c075261..adabc6b 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2001-2002  MontaVista Software Inc.
  *    Author: Yoichi Yuasa <yyuasa@mvista.com or source@mvista.com>
- *  Copyright (C) 2003-2005  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
+ *  Copyright (C) 2003-2006  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -68,6 +68,7 @@ static unsigned char sysint2_assign[16] = {
 #define MPIUINTREG     0x0e
 #define MAIUINTREG     0x10
 #define MKIUINTREG     0x12
+#define MMACINTREG     0x12
 #define MGIUINTLREG    0x14
 #define MDSIUINTREG    0x16
 #define NMIREG         0x18
@@ -241,6 +242,30 @@ void vr41xx_disable_kiuint(uint16_t mask)
 
 EXPORT_SYMBOL(vr41xx_disable_kiuint);
 
+void vr41xx_enable_macint(uint16_t mask)
+{
+       struct irq_desc *desc = irq_desc + ETHERNET_IRQ;
+       unsigned long flags;
+
+       spin_lock_irqsave(&desc->lock, flags);
+       icu1_set(MMACINTREG, mask);
+       spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(vr41xx_enable_macint);
+
+void vr41xx_disable_macint(uint16_t mask)
+{
+       struct irq_desc *desc = irq_desc + ETHERNET_IRQ;
+       unsigned long flags;
+
+       spin_lock_irqsave(&desc->lock, flags);
+       icu1_clear(MMACINTREG, mask);
+       spin_unlock_irqrestore(&desc->lock, flags);
+}
+
+EXPORT_SYMBOL(vr41xx_disable_macint);
+
 void vr41xx_enable_dsiuint(uint16_t mask)
 {
        struct irq_desc *desc = irq_desc + DSIU_IRQ;
@@ -428,7 +453,7 @@ static void enable_sysint1_irq(unsigned int irq)
 }
 
 static struct irq_chip sysint1_irq_type = {
-       .typename       = "SYSINT1",
+       .name           = "SYSINT1",
        .ack            = disable_sysint1_irq,
        .mask           = disable_sysint1_irq,
        .mask_ack       = disable_sysint1_irq,
@@ -446,7 +471,7 @@ static void enable_sysint2_irq(unsigned int irq)
 }
 
 static struct irq_chip sysint2_irq_type = {
-       .typename       = "SYSINT2",
+       .name           = "SYSINT2",
        .ack            = disable_sysint2_irq,
        .mask           = disable_sysint2_irq,
        .mask_ack       = disable_sysint2_irq,
index a2e285c..4f97e0b 100644 (file)
@@ -81,7 +81,6 @@ void __init prom_init(void)
        }
 }
 
-unsigned long __init prom_free_prom_memory (void)
+void __init prom_free_prom_memory(void)
 {
-       return 0UL;
 }
index 16decf4..cba36a2 100644 (file)
@@ -95,27 +95,27 @@ asmlinkage void plat_irq_dispatch(void)
        unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;
 
        if (pending & CAUSEF_IP7)
-               do_IRQ(7);
+               do_IRQ(TIMER_IRQ);
        else if (pending & 0x7800) {
                if (pending & CAUSEF_IP3)
-                       irq_dispatch(3);
+                       irq_dispatch(INT1_IRQ);
                else if (pending & CAUSEF_IP4)
-                       irq_dispatch(4);
+                       irq_dispatch(INT2_IRQ);
                else if (pending & CAUSEF_IP5)
-                       irq_dispatch(5);
+                       irq_dispatch(INT3_IRQ);
                else if (pending & CAUSEF_IP6)
-                       irq_dispatch(6);
+                       irq_dispatch(INT4_IRQ);
        } else if (pending & CAUSEF_IP2)
-               irq_dispatch(2);
+               irq_dispatch(INT0_IRQ);
        else if (pending & CAUSEF_IP0)
-               do_IRQ(0);
+               do_IRQ(MIPS_SOFTINT0_IRQ);
        else if (pending & CAUSEF_IP1)
-               do_IRQ(1);
+               do_IRQ(MIPS_SOFTINT1_IRQ);
        else
                spurious_interrupt();
 }
 
 void __init arch_init_irq(void)
 {
-       mips_cpu_irq_init(MIPS_CPU_IRQ_BASE);
+       mips_cpu_irq_init();
 }
index 128ed8d..7d2d076 100644 (file)
 #include <linux/interrupt.h>
 
 #include <asm/io.h>
+#include <asm/i8259.h>
 #include <asm/vr41xx/cmbvr4133.h>
 
-extern void enable_8259A_irq(unsigned int irq);
-extern void disable_8259A_irq(unsigned int irq);
-extern void mask_and_ack_8259A(unsigned int irq);
-extern void init_8259A(int hoge);
-
 extern int vr4133_rockhopper;
 
-static void enable_i8259_irq(unsigned int irq)
-{
-       enable_8259A_irq(irq - I8259_IRQ_BASE);
-}
-
-static void disable_i8259_irq(unsigned int irq)
-{
-       disable_8259A_irq(irq - I8259_IRQ_BASE);
-}
-
-static void ack_i8259_irq(unsigned int irq)
-{
-       mask_and_ack_8259A(irq - I8259_IRQ_BASE);
-}
-
-static struct irq_chip i8259_irq_type = {
-       .typename       = "XT-PIC",
-       .ack            = ack_i8259_irq,
-       .mask           = disable_i8259_irq,
-       .mask_ack       = ack_i8259_irq,
-       .unmask         = enable_i8259_irq,
-};
-
 static int i8259_get_irq_number(int irq)
 {
-       unsigned long isr;
-
-       isr = inb(0x20);
-       irq = ffz(~isr);
-       if (irq == 2) {
-               isr = inb(0xa0);
-               irq = 8 + ffz(~isr);
-       }
-
-       if (irq < 0 || irq > 15)
-               return -EINVAL;
-
-       return I8259_IRQ_BASE + irq;
+       return i8259_irq();
 }
 
-static struct irqaction i8259_slave_cascade = {
-       .handler        = &no_action,
-       .name           = "cascade",
-};
-
 void __init rockhopper_init_irq(void)
 {
        int i;
@@ -84,11 +40,6 @@ void __init rockhopper_init_irq(void)
                return;
        }
 
-       for (i = I8259_IRQ_BASE; i <= I8259_IRQ_LAST; i++)
-               set_irq_chip_and_handler(i, &i8259_irq_type, handle_level_irq);
-
-       setup_irq(I8259_SLAVE_IRQ, &i8259_slave_cascade);
-
        vr41xx_set_irq_trigger(CMBVR41XX_INTC_PIN, TRIGGER_LEVEL, SIGNAL_THROUGH);
        vr41xx_set_irq_level(CMBVR41XX_INTC_PIN, LEVEL_HIGH);
        vr41xx_cascade_irq(CMBVR41XX_INTC_IRQ, i8259_get_irq_number);
index abc6bd2..f08e80a 100644 (file)
@@ -552,6 +552,11 @@ config PPC_PS3
        bool "Sony PS3 (incomplete)"
        depends on PPC_MULTIPLATFORM && PPC64
        select PPC_CELL
+       select USB_ARCH_HAS_OHCI
+       select USB_OHCI_LITTLE_ENDIAN
+       select USB_OHCI_BIG_ENDIAN_MMIO
+       select USB_ARCH_HAS_EHCI
+       select USB_EHCI_BIG_ENDIAN_MMIO
        help
          This option enables support for the Sony PS3 game console
          and other platforms using the PS3 hypervisor.
index 6828df4..7e97d71 100644 (file)
@@ -381,8 +381,6 @@ struct pci_dev *of_create_pci_dev(struct device_node *node,
 
        pci_device_add(dev, bus);
 
-       /* XXX pci_scan_msi_device(dev); */
-
        return dev;
 }
 EXPORT_SYMBOL(of_create_pci_dev);
index 1227236..eaed402 100644 (file)
@@ -34,10 +34,6 @@ config GENERIC_HWEIGHT
        bool
        default y
 
-config GENERIC_CALIBRATE_DELAY
-       bool
-       default y
-
 config GENERIC_TIME
        def_bool y
 
@@ -134,6 +130,31 @@ config AUDIT_ARCH
        bool
        default y
 
+config S390_SWITCH_AMODE
+       bool "Switch kernel/user addressing modes"
+       help
+         This option allows to switch the addressing modes of kernel and user
+         space. The kernel parameter switch_amode=on will enable this feature,
+         default is disabled. Enabling this (via kernel parameter) on machines
+         earlier than IBM System z9-109 EC/BC will reduce system performance.
+
+         Note that this option will also be selected by selecting the execute
+         protection option below. Enabling the execute protection via the
+         noexec kernel parameter will also switch the addressing modes,
+         independent of the switch_amode kernel parameter.
+
+
+config S390_EXEC_PROTECT
+       bool "Data execute protection"
+       select S390_SWITCH_AMODE
+       help
+         This option allows to enable a buffer overflow protection for user
+         space programs and it also selects the addressing mode option above.
+         The kernel parameter noexec=on will enable this feature and also
+         switch the addressing modes, default is disabled. Enabling this (via
+         kernel parameter) on machines earlier than IBM System z9-109 EC/BC
+         will reduce system performance.
+
 comment "Code generation options"
 
 choice
index b8c2372..c9da7d1 100644 (file)
@@ -81,7 +81,7 @@ static struct ctl_table appldata_dir_table[] = {
 /*
  * Timer
  */
-DEFINE_PER_CPU(struct vtimer_list, appldata_timer);
+static DEFINE_PER_CPU(struct vtimer_list, appldata_timer);
 static atomic_t appldata_expire_count = ATOMIC_INIT(0);
 
 static DEFINE_SPINLOCK(appldata_timer_lock);
index 8aea369..4ca6157 100644 (file)
@@ -36,7 +36,7 @@
  * book:
  * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
  */
-struct appldata_mem_data {
+static struct appldata_mem_data {
        u64 timestamp;
        u32 sync_count_1;       /* after VM collected the record data, */
        u32 sync_count_2;       /* sync_count_1 and sync_count_2 should be the
index 075e619..f64b8c8 100644 (file)
@@ -34,7 +34,7 @@
  * book:
  * http://oss.software.ibm.com/developerworks/opensource/linux390/index.shtml
  */
-struct appldata_net_sum_data {
+static struct appldata_net_sum_data {
        u64 timestamp;
        u32 sync_count_1;       /* after VM collected the record data, */
        u32 sync_count_2;       /* sync_count_1 and sync_count_2 should be the
diff --git a/arch/s390/crypto/Kconfig b/arch/s390/crypto/Kconfig
new file mode 100644 (file)
index 0000000..99ff9f0
--- /dev/null
@@ -0,0 +1,60 @@
+config CRYPTO_SHA1_S390
+       tristate "SHA1 digest algorithm"
+       depends on S390
+       select CRYPTO_ALGAPI
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
+
+config CRYPTO_SHA256_S390
+       tristate "SHA256 digest algorithm"
+       depends on S390
+       select CRYPTO_ALGAPI
+       help
+         This is the s390 hardware accelerated implementation of the
+         SHA256 secure hash standard (DFIPS 180-2).
+
+         This version of SHA implements a 256 bit hash with 128 bits of
+         security against collision attacks.
+
+config CRYPTO_DES_S390
+       tristate "DES and Triple DES cipher algorithms"
+       depends on S390
+       select CRYPTO_ALGAPI
+       select CRYPTO_BLKCIPHER
+       help
+         This us the s390 hardware accelerated implementation of the
+         DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
+
+config CRYPTO_AES_S390
+       tristate "AES cipher algorithms"
+       depends on S390
+       select CRYPTO_ALGAPI
+       select CRYPTO_BLKCIPHER
+       help
+         This is the s390 hardware accelerated implementation of the
+         AES cipher algorithms (FIPS-197). AES uses the Rijndael
+         algorithm.
+
+         Rijndael appears to be consistently a very good performer in
+         both hardware and software across a wide range of computing
+         environments regardless of its use in feedback or non-feedback
+         modes. Its key setup time is excellent, and its key agility is
+         good. Rijndael's very low memory requirements make it very well
+         suited for restricted-space environments, in which it also
+         demonstrates excellent performance. Rijndael's operations are
+         among the easiest to defend against power and timing attacks.
+
+         On s390 the System z9-109 currently only supports the key size
+         of 128 bit.
+
+config S390_PRNG
+       tristate "Pseudo random number generator device driver"
+       depends on S390
+       default "m"
+       help
+         Select this option if you want to use the s390 pseudo random number
+         generator. The PRNG is part of the cryptograhic processor functions
+         and uses triple-DES to generate secure random numbers like the
+         ANSI X9.17 standard. The PRNG is usable via the char device
+         /dev/prandom.
index bfe2541..14e552c 100644 (file)
@@ -6,5 +6,4 @@ obj-$(CONFIG_CRYPTO_SHA1_S390) += sha1_s390.o
 obj-$(CONFIG_CRYPTO_SHA256_S390) += sha256_s390.o
 obj-$(CONFIG_CRYPTO_DES_S390) += des_s390.o des_check_key.o
 obj-$(CONFIG_CRYPTO_AES_S390) += aes_s390.o
-
-obj-$(CONFIG_CRYPTO_TEST) += crypt_s390_query.o
+obj-$(CONFIG_S390_PRNG) += prng.o
index 15c9eec..9163635 100644 (file)
@@ -4,7 +4,7 @@
  * s390 implementation of the AES Cipher Algorithm.
  *
  * s390 Version:
- *   Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation
+ *   Copyright IBM Corp. 2005,2007
  *   Author(s): Jan Glauber (jang@de.ibm.com)
  *
  * Derived from "crypto/aes.c"
 /* data block size for all key lengths */
 #define AES_BLOCK_SIZE         16
 
-int has_aes_128 = 0;
-int has_aes_192 = 0;
-int has_aes_256 = 0;
+#define AES_KEYLEN_128         1
+#define AES_KEYLEN_192         2
+#define AES_KEYLEN_256         4
+
+static char keylen_flag = 0;
 
 struct s390_aes_ctx {
        u8 iv[AES_BLOCK_SIZE];
@@ -47,20 +49,19 @@ static int aes_set_key(struct crypto_tfm *tfm, const u8 *in_key,
 
        switch (key_len) {
        case 16:
-               if (!has_aes_128)
+               if (!(keylen_flag & AES_KEYLEN_128))
                        goto fail;
                break;
        case 24:
-               if (!has_aes_192)
+               if (!(keylen_flag & AES_KEYLEN_192))
                        goto fail;
 
                break;
        case 32:
-               if (!has_aes_256)
+               if (!(keylen_flag & AES_KEYLEN_256))
                        goto fail;
                break;
        default:
-               /* invalid key length */
                goto fail;
                break;
        }
@@ -322,34 +323,32 @@ static int __init aes_init(void)
        int ret;
 
        if (crypt_s390_func_available(KM_AES_128_ENCRYPT))
-               has_aes_128 = 1;
+               keylen_flag |= AES_KEYLEN_128;
        if (crypt_s390_func_available(KM_AES_192_ENCRYPT))
-               has_aes_192 = 1;
+               keylen_flag |= AES_KEYLEN_192;
        if (crypt_s390_func_available(KM_AES_256_ENCRYPT))
-               has_aes_256 = 1;
+               keylen_flag |= AES_KEYLEN_256;
+
+       if (!keylen_flag)
+               return -EOPNOTSUPP;
 
-       if (!has_aes_128 && !has_aes_192 && !has_aes_256)
-               return -ENOSYS;
+       /* z9 109 and z9 BC/EC only support 128 bit key length */
+       if (keylen_flag == AES_KEYLEN_128)
+               printk(KERN_INFO
+                      "aes_s390: hardware acceleration only available for"
+                      "128 bit keys\n");
 
        ret = crypto_register_alg(&aes_alg);
-       if (ret != 0) {
-               printk(KERN_INFO "crypt_s390: aes-s390 couldn't be loaded.\n");
+       if (ret)
                goto aes_err;
-       }
 
        ret = crypto_register_alg(&ecb_aes_alg);
-       if (ret != 0) {
-               printk(KERN_INFO
-                      "crypt_s390: ecb-aes-s390 couldn't be loaded.\n");
+       if (ret)
                goto ecb_aes_err;
-       }
 
        ret = crypto_register_alg(&cbc_aes_alg);
-       if (ret != 0) {
-               printk(KERN_INFO
-                      "crypt_s390: cbc-aes-s390 couldn't be loaded.\n");
+       if (ret)
                goto cbc_aes_err;
-       }
 
 out:
        return ret;
index 2b13708..2775d26 100644 (file)
@@ -3,8 +3,9 @@
  *
  * Support for s390 cryptographic instructions.
  *
- *   Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
- *   Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ *   Copyright IBM Corp. 2003,2007
+ *   Author(s): Thomas Spatzier
+ *             Jan Glauber (jan.glauber@de.ibm.com)
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the Free
@@ -32,7 +33,8 @@ enum crypt_s390_operations {
        CRYPT_S390_KMAC = 0x0500
 };
 
-/* function codes for KM (CIPHER MESSAGE) instruction
+/*
+ * function codes for KM (CIPHER MESSAGE) instruction
  * 0x80 is the decipher modifier bit
  */
 enum crypt_s390_km_func {
@@ -51,7 +53,8 @@ enum crypt_s390_km_func {
        KM_AES_256_DECRYPT  = CRYPT_S390_KM | 0x14 | 0x80,
 };
 
-/* function codes for KMC (CIPHER MESSAGE WITH CHAINING)
+/*
+ * function codes for KMC (CIPHER MESSAGE WITH CHAINING)
  * instruction
  */
 enum crypt_s390_kmc_func {
@@ -68,9 +71,11 @@ enum crypt_s390_kmc_func {
        KMC_AES_192_DECRYPT  = CRYPT_S390_KMC | 0x13 | 0x80,
        KMC_AES_256_ENCRYPT  = CRYPT_S390_KMC | 0x14,
        KMC_AES_256_DECRYPT  = CRYPT_S390_KMC | 0x14 | 0x80,
+       KMC_PRNG             = CRYPT_S390_KMC | 0x43,
 };
 
-/* function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
+/*
+ * function codes for KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST)
  * instruction
  */
 enum crypt_s390_kimd_func {
@@ -79,7 +84,8 @@ enum crypt_s390_kimd_func {
        KIMD_SHA_256 = CRYPT_S390_KIMD | 2,
 };
 
-/* function codes for KLMD (COMPUTE LAST MESSAGE DIGEST)
+/*
+ * function codes for KLMD (COMPUTE LAST MESSAGE DIGEST)
  * instruction
  */
 enum crypt_s390_klmd_func {
@@ -88,7 +94,8 @@ enum crypt_s390_klmd_func {
        KLMD_SHA_256 = CRYPT_S390_KLMD | 2,
 };
 
-/* function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
+/*
+ * function codes for KMAC (COMPUTE MESSAGE AUTHENTICATION CODE)
  * instruction
  */
 enum crypt_s390_kmac_func {
@@ -98,229 +105,219 @@ enum crypt_s390_kmac_func {
        KMAC_TDEA_192 = CRYPT_S390_KMAC | 3
 };
 
-/* status word for s390 crypto instructions' QUERY functions */
-struct crypt_s390_query_status {
-       u64 high;
-       u64 low;
-};
-
-/*
+/**
+ * crypt_s390_km:
+ * @func: the function code passed to KM; see crypt_s390_km_func
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
  * Executes the KM (CIPHER MESSAGE) operation of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_km_func
- * @param param: address of parameter block; see POP for details on each func
- * @param dest: address of destination memory area
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- *     for encryption/decryption funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for encryption/decryption funcs
  */
-static inline int
-crypt_s390_km(long func, void* param, u8* dest, const u8* src, long src_len)
+static inline int crypt_s390_km(long func, void *param,
+                               u8 *dest, const u8 *src, long src_len)
 {
        register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-       register void__param asm("1") = param;
-       register const u8__src asm("2") = src;
+       register void *__param asm("1") = param;
+       register const u8 *__src asm("2") = src;
        register long __src_len asm("3") = src_len;
-       register u8__dest asm("4") = dest;
+       register u8 *__dest asm("4") = dest;
        int ret;
 
        asm volatile(
                "0:     .insn   rre,0xb92e0000,%3,%1 \n" /* KM opcode */
                "1:     brc     1,0b \n" /* handle partial completion */
-               "       ahi     %0,%h7\n"
-               "2:     ahi     %0,%h8\n"
-               "3:\n"
-               EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+               "       la      %0,0\n"
+               "2:\n"
+               EX_TABLE(0b,2b) EX_TABLE(1b,2b)
                : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
-               : "d" (__func), "a" (__param), "0" (-EFAULT),
-                 "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+               : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
        if (ret < 0)
                return ret;
        return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 }
 
-/*
+/**
+ * crypt_s390_kmc:
+ * @func: the function code passed to KM; see crypt_s390_kmc_func
+ * @param: address of parameter block; see POP for details on each func
+ * @dest: address of destination memory area
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
  * Executes the KMC (CIPHER MESSAGE WITH CHAINING) operation of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_kmc_func
- * @param param: address of parameter block; see POP for details on each func
- * @param dest: address of destination memory area
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- *     for encryption/decryption funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for encryption/decryption funcs
  */
-static inline int
-crypt_s390_kmc(long func, void* param, u8* dest, const u8* src, long src_len)
+static inline int crypt_s390_kmc(long func, void *param,
+                                u8 *dest, const u8 *src, long src_len)
 {
        register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-       register void__param asm("1") = param;
-       register const u8__src asm("2") = src;
+       register void *__param asm("1") = param;
+       register const u8 *__src asm("2") = src;
        register long __src_len asm("3") = src_len;
-       register u8__dest asm("4") = dest;
+       register u8 *__dest asm("4") = dest;
        int ret;
 
        asm volatile(
                "0:     .insn   rre,0xb92f0000,%3,%1 \n" /* KMC opcode */
                "1:     brc     1,0b \n" /* handle partial completion */
-               "       ahi     %0,%h7\n"
-               "2:     ahi     %0,%h8\n"
-               "3:\n"
-               EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+               "       la      %0,0\n"
+               "2:\n"
+               EX_TABLE(0b,2b) EX_TABLE(1b,2b)
                : "=d" (ret), "+a" (__src), "+d" (__src_len), "+a" (__dest)
-               : "d" (__func), "a" (__param), "0" (-EFAULT),
-                 "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+               : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
        if (ret < 0)
                return ret;
        return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 }
 
-/*
+/**
+ * crypt_s390_kimd:
+ * @func: the function code passed to KM; see crypt_s390_kimd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
  * Executes the KIMD (COMPUTE INTERMEDIATE MESSAGE DIGEST) operation
  * of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_kimd_func
- * @param param: address of parameter block; see POP for details on each func
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- *     for digest funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
  */
-static inline int
-crypt_s390_kimd(long func, void* param, const u8* src, long src_len)
+static inline int crypt_s390_kimd(long func, void *param,
+                                 const u8 *src, long src_len)
 {
        register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-       register void__param asm("1") = param;
-       register const u8__src asm("2") = src;
+       register void *__param asm("1") = param;
+       register const u8 *__src asm("2") = src;
        register long __src_len asm("3") = src_len;
        int ret;
 
        asm volatile(
                "0:     .insn   rre,0xb93e0000,%1,%1 \n" /* KIMD opcode */
                "1:     brc     1,0b \n" /* handle partial completion */
-               "       ahi     %0,%h6\n"
-               "2:     ahi     %0,%h7\n"
-               "3:\n"
-               EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+               "       la      %0,0\n"
+               "2:\n"
+               EX_TABLE(0b,2b) EX_TABLE(1b,2b)
                : "=d" (ret), "+a" (__src), "+d" (__src_len)
-               : "d" (__func), "a" (__param), "0" (-EFAULT),
-                 "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+               : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
        if (ret < 0)
                return ret;
        return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 }
 
-/*
+/**
+ * crypt_s390_klmd:
+ * @func: the function code passed to KM; see crypt_s390_klmd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
  * Executes the KLMD (COMPUTE LAST MESSAGE DIGEST) operation of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_klmd_func
- * @param param: address of parameter block; see POP for details on each func
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- *     for digest funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
  */
-static inline int
-crypt_s390_klmd(long func, void* param, const u8* src, long src_len)
+static inline int crypt_s390_klmd(long func, void *param,
+                                 const u8 *src, long src_len)
 {
        register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-       register void__param asm("1") = param;
-       register const u8__src asm("2") = src;
+       register void *__param asm("1") = param;
+       register const u8 *__src asm("2") = src;
        register long __src_len asm("3") = src_len;
        int ret;
 
        asm volatile(
                "0:     .insn   rre,0xb93f0000,%1,%1 \n" /* KLMD opcode */
                "1:     brc     1,0b \n" /* handle partial completion */
-               "       ahi     %0,%h6\n"
-               "2:     ahi     %0,%h7\n"
-               "3:\n"
-               EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+               "       la      %0,0\n"
+               "2:\n"
+               EX_TABLE(0b,2b) EX_TABLE(1b,2b)
                : "=d" (ret), "+a" (__src), "+d" (__src_len)
-               : "d" (__func), "a" (__param), "0" (-EFAULT),
-                 "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+               : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
        if (ret < 0)
                return ret;
        return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 }
 
-/*
+/**
+ * crypt_s390_kmac:
+ * @func: the function code passed to KM; see crypt_s390_klmd_func
+ * @param: address of parameter block; see POP for details on each func
+ * @src: address of source memory area
+ * @src_len: length of src operand in bytes
+ *
  * Executes the KMAC (COMPUTE MESSAGE AUTHENTICATION CODE) operation
  * of the CPU.
- * @param func: the function code passed to KM; see crypt_s390_klmd_func
- * @param param: address of parameter block; see POP for details on each func
- * @param src: address of source memory area
- * @param src_len: length of src operand in bytes
- * @returns < zero for failure, 0 for the query func, number of processed bytes
- *     for digest funcs
+ *
+ * Returns -1 for failure, 0 for the query func, number of processed
+ * bytes for digest funcs
  */
-static inline int
-crypt_s390_kmac(long func, void* param, const u8* src, long src_len)
+static inline int crypt_s390_kmac(long func, void *param,
+                                 const u8 *src, long src_len)
 {
        register long __func asm("0") = func & CRYPT_S390_FUNC_MASK;
-       register void__param asm("1") = param;
-       register const u8__src asm("2") = src;
+       register void *__param asm("1") = param;
+       register const u8 *__src asm("2") = src;
        register long __src_len asm("3") = src_len;
        int ret;
 
        asm volatile(
                "0:     .insn   rre,0xb91e0000,%1,%1 \n" /* KLAC opcode */
                "1:     brc     1,0b \n" /* handle partial completion */
-               "       ahi     %0,%h6\n"
-               "2:     ahi     %0,%h7\n"
-               "3:\n"
-               EX_TABLE(0b,3b) EX_TABLE(1b,2b)
+               "       la      %0,0\n"
+               "2:\n"
+               EX_TABLE(0b,2b) EX_TABLE(1b,2b)
                : "=d" (ret), "+a" (__src), "+d" (__src_len)
-               : "d" (__func), "a" (__param), "0" (-EFAULT),
-                 "K" (ENOSYS), "K" (-ENOSYS + EFAULT) : "cc", "memory");
+               : "d" (__func), "a" (__param), "0" (-1) : "cc", "memory");
        if (ret < 0)
                return ret;
        return (func & CRYPT_S390_FUNC_MASK) ? src_len - __src_len : __src_len;
 }
 
 /**
+ * crypt_s390_func_available:
+ * @func: the function code of the specific function; 0 if op in general
+ *
  * Tests if a specific crypto function is implemented on the machine.
- * @param func:        the function code of the specific function; 0 if op in general
- * @return     1 if func available; 0 if func or op in general not available
+ *
+ * Returns 1 if func available; 0 if func or op in general not available
  */
-static inline int
-crypt_s390_func_available(int func)
+static inline int crypt_s390_func_available(int func)
 {
+       unsigned char status[16];
        int ret;
 
-       struct crypt_s390_query_status status = {
-               .high = 0,
-               .low = 0
-       };
-       switch (func & CRYPT_S390_OP_MASK){
-               case CRYPT_S390_KM:
-                       ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
-                       break;
-               case CRYPT_S390_KMC:
-                       ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
-                       break;
-               case CRYPT_S390_KIMD:
-                       ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
-                       break;
-               case CRYPT_S390_KLMD:
-                       ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
-                       break;
-               case CRYPT_S390_KMAC:
-                       ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
-                       break;
-               default:
-                       ret = 0;
-                       return ret;
-       }
-       if (ret >= 0){
-               func &= CRYPT_S390_FUNC_MASK;
-               func &= 0x7f; //mask modifier bit
-               if (func < 64){
-                       ret = (status.high >> (64 - func - 1)) & 0x1;
-               } else {
-                       ret = (status.low >> (128 - func - 1)) & 0x1;
-               }
-       } else {
-               ret = 0;
+       switch (func & CRYPT_S390_OP_MASK) {
+       case CRYPT_S390_KM:
+               ret = crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
+               break;
+       case CRYPT_S390_KMC:
+               ret = crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
+               break;
+       case CRYPT_S390_KIMD:
+               ret = crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
+               break;
+       case CRYPT_S390_KLMD:
+               ret = crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
+               break;
+       case CRYPT_S390_KMAC:
+               ret = crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
+               break;
+       default:
+               return 0;
        }
-       return ret;
+       if (ret < 0)
+               return 0;
+       func &= CRYPT_S390_FUNC_MASK;
+       func &= 0x7f;           /* mask modifier bit */
+       return (status[func >> 3] & (0x80 >> (func & 7))) != 0;
 }
 
-#endif // _CRYPTO_ARCH_S390_CRYPT_S390_H
+#endif /* _CRYPTO_ARCH_S390_CRYPT_S390_H */
diff --git a/arch/s390/crypto/crypt_s390_query.c b/arch/s390/crypto/crypt_s390_query.c
deleted file mode 100644 (file)
index 54fb11d..0000000
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Cryptographic API.
- *
- * Support for s390 cryptographic instructions.
- * Testing module for querying processor crypto capabilities.
- *
- * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- */
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <asm/errno.h>
-#include "crypt_s390.h"
-
-static void query_available_functions(void)
-{
-       printk(KERN_INFO "#####################\n");
-
-       /* query available KM functions */
-       printk(KERN_INFO "KM_QUERY: %d\n",
-               crypt_s390_func_available(KM_QUERY));
-       printk(KERN_INFO "KM_DEA: %d\n",
-               crypt_s390_func_available(KM_DEA_ENCRYPT));
-       printk(KERN_INFO "KM_TDEA_128: %d\n",
-               crypt_s390_func_available(KM_TDEA_128_ENCRYPT));
-       printk(KERN_INFO "KM_TDEA_192: %d\n",
-               crypt_s390_func_available(KM_TDEA_192_ENCRYPT));
-       printk(KERN_INFO "KM_AES_128: %d\n",
-               crypt_s390_func_available(KM_AES_128_ENCRYPT));
-       printk(KERN_INFO "KM_AES_192: %d\n",
-               crypt_s390_func_available(KM_AES_192_ENCRYPT));
-       printk(KERN_INFO "KM_AES_256: %d\n",
-               crypt_s390_func_available(KM_AES_256_ENCRYPT));
-
-       /* query available KMC functions */
-       printk(KERN_INFO "KMC_QUERY: %d\n",
-               crypt_s390_func_available(KMC_QUERY));
-       printk(KERN_INFO "KMC_DEA: %d\n",
-               crypt_s390_func_available(KMC_DEA_ENCRYPT));
-       printk(KERN_INFO "KMC_TDEA_128: %d\n",
-               crypt_s390_func_available(KMC_TDEA_128_ENCRYPT));
-       printk(KERN_INFO "KMC_TDEA_192: %d\n",
-               crypt_s390_func_available(KMC_TDEA_192_ENCRYPT));
-       printk(KERN_INFO "KMC_AES_128: %d\n",
-               crypt_s390_func_available(KMC_AES_128_ENCRYPT));
-       printk(KERN_INFO "KMC_AES_192: %d\n",
-               crypt_s390_func_available(KMC_AES_192_ENCRYPT));
-       printk(KERN_INFO "KMC_AES_256: %d\n",
-               crypt_s390_func_available(KMC_AES_256_ENCRYPT));
-
-       /* query available KIMD functions */
-       printk(KERN_INFO "KIMD_QUERY: %d\n",
-               crypt_s390_func_available(KIMD_QUERY));
-       printk(KERN_INFO "KIMD_SHA_1: %d\n",
-               crypt_s390_func_available(KIMD_SHA_1));
-       printk(KERN_INFO "KIMD_SHA_256: %d\n",
-               crypt_s390_func_available(KIMD_SHA_256));
-
-       /* query available KLMD functions */
-       printk(KERN_INFO "KLMD_QUERY: %d\n",
-               crypt_s390_func_available(KLMD_QUERY));
-       printk(KERN_INFO "KLMD_SHA_1: %d\n",
-               crypt_s390_func_available(KLMD_SHA_1));
-       printk(KERN_INFO "KLMD_SHA_256: %d\n",
-               crypt_s390_func_available(KLMD_SHA_256));
-
-       /* query available KMAC functions */
-       printk(KERN_INFO "KMAC_QUERY: %d\n",
-               crypt_s390_func_available(KMAC_QUERY));
-       printk(KERN_INFO "KMAC_DEA: %d\n",
-               crypt_s390_func_available(KMAC_DEA));
-       printk(KERN_INFO "KMAC_TDEA_128: %d\n",
-               crypt_s390_func_available(KMAC_TDEA_128));
-       printk(KERN_INFO "KMAC_TDEA_192: %d\n",
-               crypt_s390_func_available(KMAC_TDEA_192));
-}
-
-static int init(void)
-{
-       struct crypt_s390_query_status status = {
-               .high = 0,
-               .low = 0
-       };
-
-       printk(KERN_INFO "crypt_s390: querying available crypto functions\n");
-       crypt_s390_km(KM_QUERY, &status, NULL, NULL, 0);
-       printk(KERN_INFO "KM:\t%016llx %016llx\n",
-                       (unsigned long long) status.high,
-                       (unsigned long long) status.low);
-       status.high = status.low = 0;
-       crypt_s390_kmc(KMC_QUERY, &status, NULL, NULL, 0);
-       printk(KERN_INFO "KMC:\t%016llx %016llx\n",
-                       (unsigned long long) status.high,
-                       (unsigned long long) status.low);
-       status.high = status.low = 0;
-       crypt_s390_kimd(KIMD_QUERY, &status, NULL, 0);
-       printk(KERN_INFO "KIMD:\t%016llx %016llx\n",
-                       (unsigned long long) status.high,
-                       (unsigned long long) status.low);
-       status.high = status.low = 0;
-       crypt_s390_klmd(KLMD_QUERY, &status, NULL, 0);
-       printk(KERN_INFO "KLMD:\t%016llx %016llx\n",
-                       (unsigned long long) status.high,
-                       (unsigned long long) status.low);
-       status.high = status.low = 0;
-       crypt_s390_kmac(KMAC_QUERY, &status, NULL, 0);
-       printk(KERN_INFO "KMAC:\t%016llx %016llx\n",
-                       (unsigned long long) status.high,
-                       (unsigned long long) status.low);
-
-       query_available_functions();
-       return -ECANCELED;
-}
-
-static void __exit cleanup(void)
-{
-}
-
-module_init(init);
-module_exit(cleanup);
-
-MODULE_LICENSE("GPL");
index e3f5c5f..5706af2 100644 (file)
@@ -10,8 +10,9 @@
  * scatterlist interface.  Changed LGPL to GPL per section 3 of the LGPL.
  *
  * s390 Version:
- *   Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
- *   Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ *   Copyright IBM Corp. 2003
+ *   Author(s): Thomas Spatzier
+ *             Jan Glauber (jan.glauber@de.ibm.com)
  *
  * Derived from "crypto/des.c"
  *   Copyright (c) 1992 Dana L. How.
@@ -30,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/crypto.h>
+#include "crypto_des.h"
 
 #define ROR(d,c,o)     ((d) = (d) >> (c) | (d) << (o))
 
index 2aba048..ea22707 100644 (file)
@@ -3,9 +3,9 @@
  *
  * s390 implementation of the DES Cipher Algorithm.
  *
- * Copyright (c) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
- *
+ * Copyright IBM Corp. 2003,2007
+ * Author(s): Thomas Spatzier
+ *           Jan Glauber (jan.glauber@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
@@ -557,7 +557,7 @@ static int init(void)
        if (!crypt_s390_func_available(KM_DEA_ENCRYPT) ||
            !crypt_s390_func_available(KM_TDEA_128_ENCRYPT) ||
            !crypt_s390_func_available(KM_TDEA_192_ENCRYPT))
-               return -ENOSYS;
+               return -EOPNOTSUPP;
 
        ret = crypto_register_alg(&des_alg);
        if (ret)
diff --git a/arch/s390/crypto/prng.c b/arch/s390/crypto/prng.c
new file mode 100644 (file)
index 0000000..8eb3a1a
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright IBM Corp. 2006,2007
+ * Author(s): Jan Glauber <jan.glauber@de.ibm.com>
+ * Driver for the s390 pseudo random number generator
+ */
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/random.h>
+#include <asm/debug.h>
+#include <asm/uaccess.h>
+
+#include "crypt_s390.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jan Glauber <jan.glauber@de.ibm.com>");
+MODULE_DESCRIPTION("s390 PRNG interface");
+
+static int prng_chunk_size = 256;
+module_param(prng_chunk_size, int, S_IRUSR | S_IRGRP | S_IROTH);
+MODULE_PARM_DESC(prng_chunk_size, "PRNG read chunk size in bytes");
+
+static int prng_entropy_limit = 4096;
+module_param(prng_entropy_limit, int, S_IRUSR | S_IRGRP | S_IROTH | S_IWUSR);
+MODULE_PARM_DESC(prng_entropy_limit,
+       "PRNG add entropy after that much bytes were produced");
+
+/*
+ * Any one who considers arithmetical methods of producing random digits is,
+ * of course, in a state of sin. -- John von Neumann
+ */
+
+struct s390_prng_data {
+       unsigned long count; /* how many bytes were produced */
+       char *buf;
+};
+
+static struct s390_prng_data *p;
+
+/* copied from libica, use a non-zero initial parameter block */
+static unsigned char parm_block[32] = {
+0x0F,0x2B,0x8E,0x63,0x8C,0x8E,0xD2,0x52,0x64,0xB7,0xA0,0x7B,0x75,0x28,0xB8,0xF4,
+0x75,0x5F,0xD2,0xA6,0x8D,0x97,0x11,0xFF,0x49,0xD8,0x23,0xF3,0x7E,0x21,0xEC,0xA0,
+};
+
+static int prng_open(struct inode *inode, struct file *file)
+{
+       return nonseekable_open(inode, file);
+}
+
+static void prng_add_entropy(void)
+{
+       __u64 entropy[4];
+       unsigned int i;
+       int ret;
+
+       for (i = 0; i < 16; i++) {
+               ret = crypt_s390_kmc(KMC_PRNG, parm_block, (char *)entropy,
+                                    (char *)entropy, sizeof(entropy));
+               BUG_ON(ret < 0 || ret != sizeof(entropy));
+               memcpy(parm_block, entropy, sizeof(entropy));
+       }
+}
+
+static void prng_seed(int nbytes)
+{
+       char buf[16];
+       int i = 0;
+
+       BUG_ON(nbytes > 16);
+       get_random_bytes(buf, nbytes);
+
+       /* Add the entropy */
+       while (nbytes >= 8) {
+               *((__u64 *)parm_block) ^= *((__u64 *)buf+i*8);
+               prng_add_entropy();
+               i += 8;
+               nbytes -= 8;
+       }
+       prng_add_entropy();
+}
+
+static ssize_t prng_read(struct file *file, char __user *ubuf, size_t nbytes,
+                        loff_t *ppos)
+{
+       int chunk, n;
+       int ret = 0;
+       int tmp;
+
+       /* nbytes can be arbitrary long, we spilt it into chunks */
+       while (nbytes) {
+               /* same as in extract_entropy_user in random.c */
+               if (need_resched()) {
+                       if (signal_pending(current)) {
+                               if (ret == 0)
+                                       ret = -ERESTARTSYS;
+                               break;
+                       }
+                       schedule();
+               }
+
+               /*
+                * we lose some random bytes if an attacker issues
+                * reads < 8 bytes, but we don't care
+                */
+               chunk = min_t(int, nbytes, prng_chunk_size);
+
+               /* PRNG only likes multiples of 8 bytes */
+               n = (chunk + 7) & -8;
+
+               if (p->count > prng_entropy_limit)
+                       prng_seed(8);
+
+               /* if the CPU supports PRNG stckf is present too */
+               asm volatile(".insn     s,0xb27c0000,%0"
+                            : "=m" (*((unsigned long long *)p->buf)) : : "cc");
+
+               /*
+                * Beside the STCKF the input for the TDES-EDE is the output
+                * of the last operation. We differ here from X9.17 since we
+                * only store one timestamp into the buffer. Padding the whole
+                * buffer with timestamps does not improve security, since
+                * successive stckf have nearly constant offsets.
+                * If an attacker knows the first timestamp it would be
+                * trivial to guess the additional values. One timestamp
+                * is therefore enough and still guarantees unique input values.
+                *
+                * Note: you can still get strict X9.17 conformity by setting
+                * prng_chunk_size to 8 bytes.
+               */
+               tmp = crypt_s390_kmc(KMC_PRNG, parm_block, p->buf, p->buf, n);
+               BUG_ON((tmp < 0) || (tmp != n));
+
+               p->count += n;
+
+               if (copy_to_user(ubuf, p->buf, chunk))
+                       return -EFAULT;
+
+               nbytes -= chunk;
+               ret += chunk;
+               ubuf += chunk;
+       }
+       return ret;
+}
+
+static struct file_operations prng_fops = {
+       .owner          = THIS_MODULE,
+       .open           = &prng_open,
+       .release        = NULL,
+       .read           = &prng_read,
+};
+
+static struct miscdevice prng_dev = {
+       .name   = "prandom",
+       .minor  = MISC_DYNAMIC_MINOR,
+       .fops   = &prng_fops,
+};
+
+static int __init prng_init(void)
+{
+       int ret;
+
+       /* check if the CPU has a PRNG */
+       if (!crypt_s390_func_available(KMC_PRNG))
+               return -EOPNOTSUPP;
+
+       if (prng_chunk_size < 8)
+               return -EINVAL;
+
+       p = kmalloc(sizeof(struct s390_prng_data), GFP_KERNEL);
+       if (!p)
+               return -ENOMEM;
+       p->count = 0;
+
+       p->buf = kmalloc(prng_chunk_size, GFP_KERNEL);
+       if (!p->buf) {
+               ret = -ENOMEM;
+               goto out_free;
+       }
+
+       /* initialize the PRNG, add 128 bits of entropy */
+       prng_seed(16);
+
+       ret = misc_register(&prng_dev);
+       if (ret) {
+               printk(KERN_WARNING
+                      "Could not register misc device for PRNG.\n");
+               goto out_buf;
+       }
+       return 0;
+
+out_buf:
+       kfree(p->buf);
+out_free:
+       kfree(p);
+       return ret;
+}
+
+static void __exit prng_exit(void)
+{
+       /* wipe me */
+       memset(p->buf, 0, prng_chunk_size);
+       kfree(p->buf);
+       kfree(p);
+
+       misc_deregister(&prng_dev);
+}
+
+module_init(prng_init);
+module_exit(prng_exit);
index 49ca869..969639f 100644 (file)
@@ -8,8 +8,9 @@
  * implementation written by Steve Reid.
  *
  * s390 Version:
- *   Copyright (C) 2003 IBM Deutschland GmbH, IBM Corporation
- *   Author(s): Thomas Spatzier (tspat@de.ibm.com)
+ *   Copyright IBM Corp. 2003,2007
+ *   Author(s): Thomas Spatzier
+ *             Jan Glauber (jan.glauber@de.ibm.com)
  *
  * Derived from "crypto/sha1.c"
  *   Copyright (c) Alan Smithee.
@@ -43,16 +44,14 @@ struct crypt_s390_sha1_ctx {
 static void sha1_init(struct crypto_tfm *tfm)
 {
        struct crypt_s390_sha1_ctx *ctx = crypto_tfm_ctx(tfm);
-       static const u32 initstate[5] = {
-               0x67452301,
-               0xEFCDAB89,
-               0x98BADCFE,
-               0x10325476,
-               0xC3D2E1F0
-       };
+
+       ctx->state[0] = 0x67452301;
+       ctx->state[1] = 0xEFCDAB89;
+       ctx->state[2] = 0x98BADCFE;
+       ctx->state[3] = 0x10325476;
+       ctx->state[4] = 0xC3D2E1F0;
 
        ctx->count = 0;
-       memcpy(ctx->state, &initstate, sizeof(initstate));
        ctx->buf_len = 0;
 }
 
@@ -63,13 +62,13 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
        long imd_len;
 
        sctx = crypto_tfm_ctx(tfm);
-       sctx->count += len * 8; //message bit length
+       sctx->count += len * 8; /* message bit length */
 
-       //anything in buffer yet? -> must be completed
+       /* anything in buffer yet? -> must be completed */
        if (sctx->buf_len && (sctx->buf_len + len) >= SHA1_BLOCK_SIZE) {
-               //complete full block and hash
+               /* complete full block and hash */
                memcpy(sctx->buffer + sctx->buf_len, data,
-                               SHA1_BLOCK_SIZE - sctx->buf_len);
+                      SHA1_BLOCK_SIZE - sctx->buf_len);
                crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer,
                                SHA1_BLOCK_SIZE);
                data += SHA1_BLOCK_SIZE - sctx->buf_len;
@@ -77,37 +76,36 @@ static void sha1_update(struct crypto_tfm *tfm, const u8 *data,
                sctx->buf_len = 0;
        }
 
-       //rest of data contains full blocks?
+       /* rest of data contains full blocks? */
        imd_len = len & ~0x3ful;
-       if (imd_len){
+       if (imd_len) {
                crypt_s390_kimd(KIMD_SHA_1, sctx->state, data, imd_len);
                data += imd_len;
                len -= imd_len;
        }
-       //anything left? store in buffer
-       if (len){
+       /* anything left? store in buffer */
+       if (len) {
                memcpy(sctx->buffer + sctx->buf_len , data, len);
                sctx->buf_len += len;
        }
 }
 
 
-static void
-pad_message(struct crypt_s390_sha1_ctx* sctx)
+static void pad_message(struct crypt_s390_sha1_ctx* sctx)
 {
        int index;
 
        index = sctx->buf_len;
-       sctx->buf_len = (sctx->buf_len < 56)?
-               SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
-       //start pad with 1
+       sctx->buf_len = (sctx->buf_len < 56) ?
+                        SHA1_BLOCK_SIZE:2 * SHA1_BLOCK_SIZE;
+       /* start pad with 1 */
        sctx->buffer[index] = 0x80;
-       //pad with zeros
+       /* pad with zeros */
        index++;
        memset(sctx->buffer + index, 0x00, sctx->buf_len - index);
-       //append length
+       /* append length */
        memcpy(sctx->buffer + sctx->buf_len - 8, &sctx->count,
-                       sizeof sctx->count);
+              sizeof sctx->count);
 }
 
 /* Add padding and return the message digest. */
@@ -115,47 +113,40 @@ static void sha1_final(struct crypto_tfm *tfm, u8 *out)
 {
        struct crypt_s390_sha1_ctx *sctx = crypto_tfm_ctx(tfm);
 
-       //must perform manual padding
+       /* must perform manual padding */
        pad_message(sctx);
        crypt_s390_kimd(KIMD_SHA_1, sctx->state, sctx->buffer, sctx->buf_len);
-       //copy digest to out
+       /* copy digest to out */
        memcpy(out, sctx->state, SHA1_DIGEST_SIZE);
-       /* Wipe context */
+       /* wipe context */
        memset(sctx, 0, sizeof *sctx);
 }
 
 static struct crypto_alg alg = {
        .cra_name       =       "sha1",
-       .cra_driver_name =      "sha1-s390",
+       .cra_driver_name      "sha1-s390",
        .cra_priority   =       CRYPT_S390_PRIORITY,
        .cra_flags      =       CRYPTO_ALG_TYPE_DIGEST,
        .cra_blocksize  =       SHA1_BLOCK_SIZE,
        .cra_ctxsize    =       sizeof(struct crypt_s390_sha1_ctx),
        .cra_module     =       THIS_MODULE,
-       .cra_list       =       LIST_HEAD_INIT(alg.cra_list),
+       .cra_list       =       LIST_HEAD_INIT(alg.cra_list),
        .cra_u          =       { .digest = {
        .dia_digestsize =       SHA1_DIGEST_SIZE,
-       .dia_init       =       sha1_init,
-       .dia_update     =       sha1_update,
-       .dia_final      =       sha1_final } }
+       .dia_init       =       sha1_init,
+       .dia_update     =       sha1_update,
+       .dia_final      =       sha1_final } }
 };
 
-static int
-init(void)
+static int __init init(void)
 {
-       int ret = -ENOSYS;
+       if (!crypt_s390_func_available(KIMD_SHA_1))
+               return -EOPNOTSUPP;
 
-       if (crypt_s390_func_available(KIMD_SHA_1)){
-               ret = crypto_register_alg(&alg);
-               if (ret == 0){
-                       printk(KERN_INFO "crypt_s390: sha1_s390 loaded.\n");
-               }
-       }
-       return ret;
+       return crypto_register_alg(&alg);
 }
 
-static void __exit
-fini(void)
+static void __exit fini(void)
 {
        crypto_unregister_alg(&alg);
 }
index 8e4e675..78436c6 100644 (file)
@@ -4,7 +4,7 @@
  * s390 implementation of the SHA256 Secure Hash Algorithm.
  *
  * s390 Version:
- *   Copyright (C) 2005 IBM Deutschland GmbH, IBM Corporation
+ *   Copyright IBM Corp. 2005,2007
  *   Author(s): Jan Glauber (jang@de.ibm.com)
  *
  * Derived from "crypto/sha256.c"
@@ -143,15 +143,10 @@ static struct crypto_alg alg = {
 
 static int init(void)
 {
-       int ret;
-
        if (!crypt_s390_func_available(KIMD_SHA_256))
-               return -ENOSYS;
+               return -EOPNOTSUPP;
 
-       ret = crypto_register_alg(&alg);
-       if (ret != 0)
-               printk(KERN_INFO "crypt_s390: sha256_s390 couldn't be loaded.");
-       return ret;
+       return crypto_register_alg(&alg);
 }
 
 static void __exit fini(void)
index 5368cf4..7c621b8 100644 (file)
@@ -108,6 +108,8 @@ CONFIG_DEFAULT_MIGRATION_COST=1000000
 CONFIG_COMPAT=y
 CONFIG_SYSVIPC_COMPAT=y
 CONFIG_AUDIT_ARCH=y
+CONFIG_S390_SWITCH_AMODE=y
+CONFIG_S390_EXEC_PROTECT=y
 
 #
 # Code generation options
@@ -431,7 +433,6 @@ CONFIG_TN3270_CONSOLE=y
 CONFIG_TN3215=y
 CONFIG_TN3215_CONSOLE=y
 CONFIG_CCW_CONSOLE=y
-CONFIG_SCLP=y
 CONFIG_SCLP_TTY=y
 CONFIG_SCLP_CONSOLE=y
 CONFIG_SCLP_VT220_TTY=y
@@ -724,9 +725,7 @@ CONFIG_CRYPTO_MANAGER=y
 # CONFIG_CRYPTO_MD4 is not set
 # CONFIG_CRYPTO_MD5 is not set
 # CONFIG_CRYPTO_SHA1 is not set
-# CONFIG_CRYPTO_SHA1_S390 is not set
 # CONFIG_CRYPTO_SHA256 is not set
-# CONFIG_CRYPTO_SHA256_S390 is not set
 # CONFIG_CRYPTO_SHA512 is not set
 # CONFIG_CRYPTO_WP512 is not set
 # CONFIG_CRYPTO_TGR192 is not set
@@ -735,12 +734,10 @@ CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=y
 # CONFIG_CRYPTO_LRW is not set
 # CONFIG_CRYPTO_DES is not set
-# CONFIG_CRYPTO_DES_S390 is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
 # CONFIG_CRYPTO_TWOFISH is not set
 # CONFIG_CRYPTO_SERPENT is not set
 # CONFIG_CRYPTO_AES is not set
-# CONFIG_CRYPTO_AES_S390 is not set
 # CONFIG_CRYPTO_CAST5 is not set
 # CONFIG_CRYPTO_CAST6 is not set
 # CONFIG_CRYPTO_TEA is not set
@@ -755,6 +752,11 @@ CONFIG_CRYPTO_CBC=y
 #
 # Hardware crypto devices
 #
+# CONFIG_CRYPTO_SHA1_S390 is not set
+# CONFIG_CRYPTO_SHA256_S390 is not set
+# CONFIG_CRYPTO_DES_S390 is not set
+# CONFIG_CRYPTO_AES_S390 is not set
+CONFIG_S390_PRNG=m
 
 #
 # Library routines
index f4b00cd..b08d2ab 100644 (file)
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
 
-s390_hypfs-objs := inode.o hypfs_diag.o
+s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o
index f3dbd91..aea5720 100644 (file)
@@ -27,4 +27,13 @@ extern struct dentry *hypfs_create_str(struct super_block *sb,
                                       struct dentry *dir, const char *name,
                                       char *string);
 
+/* LPAR Hypervisor */
+extern int hypfs_diag_init(void);
+extern void hypfs_diag_exit(void);
+extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
+
+/* VM Hypervisor */
+extern int hypfs_vm_init(void);
+extern int hypfs_vm_create_files(struct super_block *sb, struct dentry *root);
+
 #endif /* _HYPFS_H_ */
diff --git a/arch/s390/hypfs/hypfs_diag.h b/arch/s390/hypfs/hypfs_diag.h
deleted file mode 100644 (file)
index 256b384..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *  arch/s390/hypfs_diag.h
- *    Hypervisor filesystem for Linux on s390.
- *
- *    Copyright (C) IBM Corp. 2006
- *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
- */
-
-#ifndef _HYPFS_DIAG_H_
-#define _HYPFS_DIAG_H_
-
-extern int hypfs_diag_init(void);
-extern void hypfs_diag_exit(void);
-extern int hypfs_diag_create_files(struct super_block *sb, struct dentry *root);
-
-#endif /* _HYPFS_DIAG_H_ */
diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c
new file mode 100644 (file)
index 0000000..d01fc8f
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ *    Hypervisor filesystem for Linux on s390. z/VM implementation.
+ *
+ *    Copyright (C) IBM Corp. 2006
+ *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/vmalloc.h>
+#include <asm/ebcdic.h>
+#include "hypfs.h"
+
+#define NAME_LEN 8
+
+static char local_guest[] = "        ";
+static char all_guests[] = "*       ";
+static char *guest_query;
+
+struct diag2fc_data {
+       __u32 version;
+       __u32 flags;
+       __u64 used_cpu;
+       __u64 el_time;
+       __u64 mem_min_kb;
+       __u64 mem_max_kb;
+       __u64 mem_share_kb;
+       __u64 mem_used_kb;
+       __u32 pcpus;
+       __u32 lcpus;
+       __u32 vcpus;
+       __u32 cpu_min;
+       __u32 cpu_max;
+       __u32 cpu_shares;
+       __u32 cpu_use_samp;
+       __u32 cpu_delay_samp;
+       __u32 page_wait_samp;
+       __u32 idle_samp;
+       __u32 other_samp;
+       __u32 total_samp;
+       char  guest_name[NAME_LEN];
+};
+
+struct diag2fc_parm_list {
+       char userid[NAME_LEN];
+       char aci_grp[NAME_LEN];
+       __u64 addr;
+       __u32 size;
+       __u32 fmt;
+};
+
+static int diag2fc(int size, char* query, void *addr)
+{
+       unsigned long residual_cnt;
+       unsigned long rc;
+       struct diag2fc_parm_list parm_list;
+
+       memcpy(parm_list.userid, query, NAME_LEN);
+       ASCEBC(parm_list.userid, NAME_LEN);
+       parm_list.addr = (unsigned long) addr ;
+       parm_list.size = size;
+       parm_list.fmt = 0x02;
+       memset(parm_list.aci_grp, 0x40, NAME_LEN);
+       rc = -1;
+
+       asm volatile(
+               "       diag    %0,%1,0x2fc\n"
+               "0:\n"
+               EX_TABLE(0b,0b)
+               : "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
+
+       if ((rc != 0 ) && (rc != -2))
+               return rc;
+       else
+               return -residual_cnt;
+}
+
+static struct diag2fc_data *diag2fc_store(char *query, int *count)
+{
+       int size;
+       struct diag2fc_data *data;
+
+       do {
+               size = diag2fc(0, query, NULL);
+               if (size < 0)
+                       return ERR_PTR(-EACCES);
+               data = vmalloc(size);
+               if (!data)
+                       return ERR_PTR(-ENOMEM);
+               if (diag2fc(size, query, data) == 0)
+                       break;
+               vfree(data);
+       } while (1);
+       *count = (size / sizeof(*data));
+
+       return data;
+}
+
+static void diag2fc_free(void *data)
+{
+       vfree(data);
+}
+
+#define ATTRIBUTE(sb, dir, name, member) \
+do { \
+       void *rc; \
+       rc = hypfs_create_u64(sb, dir, name, member); \
+       if (IS_ERR(rc)) \
+               return PTR_ERR(rc); \
+} while(0)
+
+static int hpyfs_vm_create_guest(struct super_block *sb,
+                                struct dentry *systems_dir,
+                                struct diag2fc_data *data)
+{
+       char guest_name[NAME_LEN + 1] = {};
+       struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
+       int dedicated_flag, capped_value;
+
+       capped_value = (data->flags & 0x00000006) >> 1;
+       dedicated_flag = (data->flags & 0x00000008) >> 3;
+
+       /* guest dir */
+       memcpy(guest_name, data->guest_name, NAME_LEN);
+       EBCASC(guest_name, NAME_LEN);
+       strstrip(guest_name);
+       guest_dir = hypfs_mkdir(sb, systems_dir, guest_name);
+       if (IS_ERR(guest_dir))
+               return PTR_ERR(guest_dir);
+       ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time);
+
+       /* logical cpu information */
+       cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus");
+       if (IS_ERR(cpus_dir))
+               return PTR_ERR(cpus_dir);
+       ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu);
+       ATTRIBUTE(sb, cpus_dir, "capped", capped_value);
+       ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag);
+       ATTRIBUTE(sb, cpus_dir, "count", data->vcpus);
+       ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min);
+       ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max);
+       ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares);
+
+       /* memory information */
+       mem_dir = hypfs_mkdir(sb, guest_dir, "mem");
+       if (IS_ERR(mem_dir))
+               return PTR_ERR(mem_dir);
+       ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb);
+       ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb);
+       ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb);
+       ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb);
+
+       /* samples */
+       samples_dir = hypfs_mkdir(sb, guest_dir, "samples");
+       if (IS_ERR(samples_dir))
+               return PTR_ERR(samples_dir);
+       ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp);
+       ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp);
+       ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp);
+       ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp);
+       ATTRIBUTE(sb, samples_dir, "other", data->other_samp);
+       ATTRIBUTE(sb, samples_dir, "total", data->total_samp);
+       return 0;
+}
+
+int hypfs_vm_create_files(struct super_block *sb, struct dentry *root)
+{
+       struct dentry *dir, *file;
+       struct diag2fc_data *data;
+       int rc, i, count = 0;
+
+       data = diag2fc_store(guest_query, &count);
+       if (IS_ERR(data))
+               return PTR_ERR(data);
+
+       /* Hpervisor Info */
+       dir = hypfs_mkdir(sb, root, "hyp");
+       if (IS_ERR(dir)) {
+               rc = PTR_ERR(dir);
+               goto failed;
+       }
+       file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor");
+       if (IS_ERR(file)) {
+               rc = PTR_ERR(file);
+               goto failed;
+       }
+
+       /* physical cpus */
+       dir = hypfs_mkdir(sb, root, "cpus");
+       if (IS_ERR(dir)) {
+               rc = PTR_ERR(dir);
+               goto failed;
+       }
+       file = hypfs_create_u64(sb, dir, "count", data->lcpus);
+       if (IS_ERR(file)) {
+               rc = PTR_ERR(file);
+               goto failed;
+       }
+
+       /* guests */
+       dir = hypfs_mkdir(sb, root, "systems");
+       if (IS_ERR(dir)) {
+               rc = PTR_ERR(dir);
+               goto failed;
+       }
+
+       for (i = 0; i < count; i++) {
+               rc = hpyfs_vm_create_guest(sb, dir, &(data[i]));
+               if (rc)
+                       goto failed;
+       }
+       diag2fc_free(data);
+       return 0;
+
+failed:
+       diag2fc_free(data);
+       return rc;
+}
+
+int hypfs_vm_init(void)
+{
+       if (diag2fc(0, all_guests, NULL) > 0)
+               guest_query = all_guests;
+       else if (diag2fc(0, local_guest, NULL) > 0)
+               guest_query = local_guest;
+       else
+               return -EACCES;
+
+       return 0;
+}
index b6716c4..a4fda7b 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/module.h>
 #include <asm/ebcdic.h>
 #include "hypfs.h"
-#include "hypfs_diag.h"
 
 #define HYPFS_MAGIC 0x687970   /* ASCII 'hyp' */
 #define TMP_SIZE 64            /* size of temporary buffers */
@@ -192,7 +191,10 @@ static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
                goto out;
        }
        hypfs_delete_tree(sb->s_root);
-       rc = hypfs_diag_create_files(sb, sb->s_root);
+       if (MACHINE_IS_VM)
+               rc = hypfs_vm_create_files(sb, sb->s_root);
+       else
+               rc = hypfs_diag_create_files(sb, sb->s_root);
        if (rc) {
                printk(KERN_ERR "hypfs: Update failed\n");
                hypfs_delete_tree(sb->s_root);
@@ -289,7 +291,10 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
                rc = -ENOMEM;
                goto err_alloc;
        }
-       rc = hypfs_diag_create_files(sb, root_dentry);
+       if (MACHINE_IS_VM)
+               rc = hypfs_vm_create_files(sb, root_dentry);
+       else
+               rc = hypfs_diag_create_files(sb, root_dentry);
        if (rc)
                goto err_tree;
        sbi->update_file = hypfs_create_update_file(sb, root_dentry);
@@ -462,11 +467,15 @@ static int __init hypfs_init(void)
 {
        int rc;
 
-       if (MACHINE_IS_VM)
-               return -ENODATA;
-       if (hypfs_diag_init()) {
-               rc = -ENODATA;
-               goto fail_diag;
+       if (MACHINE_IS_VM) {
+               if (hypfs_vm_init())
+                       /* no diag 2fc, just exit */
+                       return -ENODATA;
+       } else {
+               if (hypfs_diag_init()) {
+                       rc = -ENODATA;
+                       goto fail_diag;
+               }
        }
        kset_set_kset_s(&s390_subsys, hypervisor_subsys);
        rc = subsystem_register(&s390_subsys);
@@ -480,7 +489,8 @@ static int __init hypfs_init(void)
 fail_filesystem:
        subsystem_unregister(&s390_subsys);
 fail_sysfs:
-       hypfs_diag_exit();
+       if (!MACHINE_IS_VM)
+               hypfs_diag_exit();
 fail_diag:
        printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc);
        return rc;
@@ -488,7 +498,8 @@ fail_diag:
 
 static void __exit hypfs_exit(void)
 {
-       hypfs_diag_exit();
+       if (!MACHINE_IS_VM)
+               hypfs_diag_exit();
        unregister_filesystem(&hypfs_type);
        subsystem_unregister(&s390_subsys);
 }
index a81881c..5492d25 100644 (file)
@@ -4,9 +4,9 @@
 
 EXTRA_AFLAGS   := -traditional
 
-obj-y  :=  bitmap.o traps.o time.o process.o reset.o \
+obj-y  :=  bitmap.o traps.o time.o process.o base.o early.o \
             setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
-           semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o
+           semaphore.o s390_ext.o debug.o irq.o ipl.o
 
 obj-y  += $(if $(CONFIG_64BIT),entry64.o,entry.o)
 obj-y  += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
diff --git a/arch/s390/kernel/base.S b/arch/s390/kernel/base.S
new file mode 100644 (file)
index 0000000..dc7e525
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ *  arch/s390/kernel/base.S
+ *
+ *    Copyright IBM Corp. 2006,2007
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ *              Michael Holzheu <holzheu@de.ibm.com>
+ */
+
+#include <asm/ptrace.h>
+#include <asm/lowcore.h>
+
+#ifdef CONFIG_64BIT
+
+       .globl  s390_base_mcck_handler
+s390_base_mcck_handler:
+       basr    %r13,0
+0:     lg      %r15,__LC_PANIC_STACK   # load panic stack
+       aghi    %r15,-STACK_FRAME_OVERHEAD
+       larl    %r1,s390_base_mcck_handler_fn
+       lg      %r1,0(%r1)
+       ltgr    %r1,%r1
+       jz      1f
+       basr    %r14,%r1
+1:     la      %r1,4095
+       lmg     %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
+       lpswe   __LC_MCK_OLD_PSW
+
+       .section .bss
+       .globl  s390_base_mcck_handler_fn
+s390_base_mcck_handler_fn:
+       .quad   0
+       .previous
+
+       .globl  s390_base_ext_handler
+s390_base_ext_handler:
+       stmg    %r0,%r15,__LC_SAVE_AREA
+       basr    %r13,0
+0:     aghi    %r15,-STACK_FRAME_OVERHEAD
+       larl    %r1,s390_base_ext_handler_fn
+       lg      %r1,0(%r1)
+       ltgr    %r1,%r1
+       jz      1f
+       basr    %r14,%r1
+1:     lmg     %r0,%r15,__LC_SAVE_AREA
+       ni      __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit
+       lpswe   __LC_EXT_OLD_PSW
+
+       .section .bss
+       .globl s390_base_ext_handler_fn
+s390_base_ext_handler_fn:
+       .quad   0
+       .previous
+
+       .globl  s390_base_pgm_handler
+s390_base_pgm_handler:
+       stmg    %r0,%r15,__LC_SAVE_AREA
+       basr    %r13,0
+0:     aghi    %r15,-STACK_FRAME_OVERHEAD
+       larl    %r1,s390_base_pgm_handler_fn
+       lg      %r1,0(%r1)
+       ltgr    %r1,%r1
+       jz      1f
+       basr    %r14,%r1
+       lmg     %r0,%r15,__LC_SAVE_AREA
+       lpswe   __LC_PGM_OLD_PSW
+1:     lpswe   disabled_wait_psw-0b(%r13)
+
+       .align  8
+disabled_wait_psw:
+       .quad   0x0002000180000000,0x0000000000000000 + s390_base_pgm_handler
+
+       .section .bss
+       .globl s390_base_pgm_handler_fn
+s390_base_pgm_handler_fn:
+       .quad   0
+       .previous
+
+#else /* CONFIG_64BIT */
+
+       .globl  s390_base_mcck_handler
+s390_base_mcck_handler:
+       basr    %r13,0
+0:     l       %r15,__LC_PANIC_STACK   # load panic stack
+       ahi     %r15,-STACK_FRAME_OVERHEAD
+       l       %r1,2f-0b(%r13)
+       l       %r1,0(%r1)
+       ltr     %r1,%r1
+       jz      1f
+       basr    %r14,%r1
+1:     lm      %r0,%r15,__LC_GPREGS_SAVE_AREA
+       lpsw    __LC_MCK_OLD_PSW
+
+2:     .long   s390_base_mcck_handler_fn
+
+       .section .bss
+       .globl  s390_base_mcck_handler_fn
+s390_base_mcck_handler_fn:
+       .long   0
+       .previous
+
+       .globl  s390_base_ext_handler
+s390_base_ext_handler:
+       stm     %r0,%r15,__LC_SAVE_AREA
+       basr    %r13,0
+0:     ahi     %r15,-STACK_FRAME_OVERHEAD
+       l       %r1,2f-0b(%r13)
+       l       %r1,0(%r1)
+       ltr     %r1,%r1
+       jz      1f
+       basr    %r14,%r1
+1:     lm      %r0,%r15,__LC_SAVE_AREA
+       ni      __LC_EXT_OLD_PSW+1,0xfd # clear wait state bit
+       lpsw    __LC_EXT_OLD_PSW
+
+2:     .long   s390_base_ext_handler_fn
+
+       .section .bss
+       .globl  s390_base_ext_handler_fn
+s390_base_ext_handler_fn:
+       .long   0
+       .previous
+
+       .globl  s390_base_pgm_handler
+s390_base_pgm_handler:
+       stm     %r0,%r15,__LC_SAVE_AREA
+       basr    %r13,0
+0:     ahi     %r15,-STACK_FRAME_OVERHEAD
+       l       %r1,2f-0b(%r13)
+       l       %r1,0(%r1)
+       ltr     %r1,%r1
+       jz      1f
+       basr    %r14,%r1
+       lm      %r0,%r15,__LC_SAVE_AREA
+       lpsw    __LC_PGM_OLD_PSW
+
+1:     lpsw    disabled_wait_psw-0b(%r13)
+
+2:     .long   s390_base_pgm_handler_fn
+
+disabled_wait_psw:
+       .align  8
+       .long   0x000a0000,0x00000000 + s390_base_pgm_handler
+
+       .section .bss
+       .globl  s390_base_pgm_handler_fn
+s390_base_pgm_handler_fn:
+       .long   0
+       .previous
+
+#endif /* CONFIG_64BIT */
index 5c46054..f1e40ca 100644 (file)
@@ -192,7 +192,7 @@ MODULE_AUTHOR("Gerhard Tonn <ton@de.ibm.com>");
 
 #undef cputime_to_timeval
 #define cputime_to_timeval cputime_to_compat_timeval
-static __inline__ void
+static inline void
 cputime_to_compat_timeval(const cputime_t cputime, struct compat_timeval *value)
 {
        value->tv_usec = cputime % 1000000;
index 71d27c4..914d494 100644 (file)
 #include <linux/personality.h>
 #include <linux/sched.h>
 
-struct exec_domain s390_exec_domain;
+static struct exec_domain s390_exec_domain;
 
-static int __init
-s390_init (void)
+static int __init s390_init (void)
 {
        s390_exec_domain.name = "Linux/s390";
        s390_exec_domain.handler = NULL;
index 5b33f82..666bb6d 100644 (file)
 
 #include "compat_linux.h"
 
+long psw_user32_bits   = (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+                          PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+                          PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
+long psw32_user_bits   = (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME |
+                          PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
+                          PSW32_MASK_PSTATE);
  
 /* For this source file, we want overflow handling. */
 
@@ -416,7 +422,7 @@ asmlinkage long sys32_sysinfo(struct sysinfo32 __user *info)
        mm_segment_t old_fs = get_fs ();
        
        set_fs (KERNEL_DS);
-       ret = sys_sysinfo((struct sysinfo __user *) &s);
+       ret = sys_sysinfo((struct sysinfo __force __user *) &s);
        set_fs (old_fs);
        err = put_user (s.uptime, &info->uptime);
        err |= __put_user (s.loads[0], &info->loads[0]);
@@ -445,7 +451,8 @@ asmlinkage long sys32_sched_rr_get_interval(compat_pid_t pid,
        mm_segment_t old_fs = get_fs ();
        
        set_fs (KERNEL_DS);
-       ret = sys_sched_rr_get_interval(pid, (struct timespec __user *) &t);
+       ret = sys_sched_rr_get_interval(pid,
+                                       (struct timespec __force __user *) &t);
        set_fs (old_fs);
        if (put_compat_timespec(&t, interval))
                return -EFAULT;
@@ -472,8 +479,8 @@ asmlinkage long sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
        }
        set_fs (KERNEL_DS);
        ret = sys_rt_sigprocmask(how,
-                                set ? (sigset_t __user *) &s : NULL,
-                                oset ? (sigset_t __user *) &s : NULL,
+                                set ? (sigset_t __force __user *) &s : NULL,
+                                oset ? (sigset_t __force __user *) &s : NULL,
                                 sigsetsize);
        set_fs (old_fs);
        if (ret) return ret;
@@ -499,7 +506,7 @@ asmlinkage long sys32_rt_sigpending(compat_sigset_t __user *set,
        mm_segment_t old_fs = get_fs();
                
        set_fs (KERNEL_DS);
-       ret = sys_rt_sigpending((sigset_t __user *) &s, sigsetsize);
+       ret = sys_rt_sigpending((sigset_t __force __user *) &s, sigsetsize);
        set_fs (old_fs);
        if (!ret) {
                switch (_NSIG_WORDS) {
@@ -524,7 +531,7 @@ sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
        if (copy_siginfo_from_user32(&info, uinfo))
                return -EFAULT;
        set_fs (KERNEL_DS);
-       ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __user *) &info);
+       ret = sys_rt_sigqueueinfo(pid, sig, (siginfo_t __force __user *) &info);
        set_fs (old_fs);
        return ret;
 }
@@ -682,7 +689,7 @@ asmlinkage long sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offse
                
        set_fs(KERNEL_DS);
        ret = sys_sendfile(out_fd, in_fd,
-                          offset ? (off_t __user *) &of : NULL, count);
+                          offset ? (off_t __force __user *) &of : NULL, count);
        set_fs(old_fs);
        
        if (offset && put_user(of, offset))
@@ -703,7 +710,8 @@ asmlinkage long sys32_sendfile64(int out_fd, int in_fd,
                
        set_fs(KERNEL_DS);
        ret = sys_sendfile64(out_fd, in_fd,
-                            offset ? (loff_t __user *) &lof : NULL, count);
+                            offset ? (loff_t __force __user *) &lof : NULL,
+                            count);
        set_fs(old_fs);
        
        if (offset && put_user(lof, offset))
index 1a18e29..e89f8c0 100644 (file)
@@ -115,37 +115,6 @@ typedef struct
         __u32  addr;
 } _psw_t32 __attribute__ ((aligned(8)));
 
-#define PSW32_MASK_PER         0x40000000UL
-#define PSW32_MASK_DAT         0x04000000UL
-#define PSW32_MASK_IO          0x02000000UL
-#define PSW32_MASK_EXT         0x01000000UL
-#define PSW32_MASK_KEY         0x00F00000UL
-#define PSW32_MASK_MCHECK      0x00040000UL
-#define PSW32_MASK_WAIT                0x00020000UL
-#define PSW32_MASK_PSTATE      0x00010000UL
-#define PSW32_MASK_ASC         0x0000C000UL
-#define PSW32_MASK_CC          0x00003000UL
-#define PSW32_MASK_PM          0x00000f00UL
-
-#define PSW32_ADDR_AMODE31     0x80000000UL
-#define PSW32_ADDR_INSN                0x7FFFFFFFUL
-
-#define PSW32_BASE_BITS                0x00080000UL
-
-#define PSW32_ASC_PRIMARY      0x00000000UL
-#define PSW32_ASC_ACCREG       0x00004000UL
-#define PSW32_ASC_SECONDARY    0x00008000UL
-#define PSW32_ASC_HOME         0x0000C000UL
-
-#define PSW32_USER_BITS        (PSW32_BASE_BITS | PSW32_MASK_DAT | PSW32_ASC_HOME | \
-                        PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK | \
-                        PSW32_MASK_PSTATE)
-
-#define PSW32_MASK_MERGE(CURRENT,NEW) \
-        (((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \
-         ((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM)))
-
-
 typedef struct
 {
        _psw_t32        psw;
index 861888a..887a988 100644 (file)
@@ -275,8 +275,8 @@ sys32_sigaltstack(const stack_t32 __user *uss, stack_t32 __user *uoss,
        }
 
        set_fs (KERNEL_DS);
-       ret = do_sigaltstack((stack_t __user *) (uss ? &kss : NULL),
-                            (stack_t __user *) (uoss ? &koss : NULL),
+       ret = do_sigaltstack((stack_t __force __user *) (uss ? &kss : NULL),
+                            (stack_t __force __user *) (uoss ? &koss : NULL),
                             regs->gprs[15]);
        set_fs (old_fs);
 
@@ -298,7 +298,7 @@ static int save_sigregs32(struct pt_regs *regs, _sigregs32 __user *sregs)
        _s390_regs_common32 regs32;
        int err, i;
 
-       regs32.psw.mask = PSW32_MASK_MERGE(PSW32_USER_BITS,
+       regs32.psw.mask = PSW32_MASK_MERGE(psw32_user_bits,
                                           (__u32)(regs->psw.mask >> 32));
        regs32.psw.addr = PSW32_ADDR_AMODE31 | (__u32) regs->psw.addr;
        for (i = 0; i < NUM_GPRS; i++)
@@ -401,7 +401,7 @@ asmlinkage long sys32_rt_sigreturn(struct pt_regs *regs)
                goto badframe; 
 
        set_fs (KERNEL_DS);
-       do_sigaltstack((stack_t __user *)&st, NULL, regs->gprs[15]);
+       do_sigaltstack((stack_t __force __user *)&st, NULL, regs->gprs[15]);
        set_fs (old_fs);
 
        return regs->gprs[2];
index a5972f1..6c89f30 100644 (file)
@@ -16,6 +16,7 @@
 #include <asm/ebcdic.h>
 #include <asm/cpcmd.h>
 #include <asm/system.h>
+#include <asm/io.h>
 
 static DEFINE_SPINLOCK(cpcmd_lock);
 static char cpcmd_buf[241];
@@ -88,13 +89,8 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
        int len;
        unsigned long flags;
 
-       if ((rlen == 0) || (response == NULL)
-           || !((unsigned long)response >> 31)) {
-               spin_lock_irqsave(&cpcmd_lock, flags);
-               len = __cpcmd(cmd, response, rlen, response_code);
-               spin_unlock_irqrestore(&cpcmd_lock, flags);
-       }
-       else {
+       if ((virt_to_phys(response) != (unsigned long) response) ||
+                       (((unsigned long)response + rlen) >> 31)) {
                lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
                if (!lowbuf) {
                        printk(KERN_WARNING
@@ -106,6 +102,10 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
                spin_unlock_irqrestore(&cpcmd_lock, flags);
                memcpy(response, lowbuf, rlen);
                kfree(lowbuf);
+       } else {
+               spin_lock_irqsave(&cpcmd_lock, flags);
+               len = __cpcmd(cmd, response, rlen, response_code);
+               spin_unlock_irqrestore(&cpcmd_lock, flags);
        }
        return len;
 }
index 926ccee..8cc7c9f 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/threads.h>
 #include <linux/kexec.h>
+#include <linux/reboot.h>
 
 void machine_crash_shutdown(struct pt_regs *regs)
 {
index bb57bc0..f4b62df 100644 (file)
@@ -120,7 +120,7 @@ struct debug_view debug_hex_ascii_view = {
        NULL
 };
 
-struct debug_view debug_level_view = {
+static struct debug_view debug_level_view = {
        "level",
        &debug_prolog_level_fn,
        NULL,
@@ -129,7 +129,7 @@ struct debug_view debug_level_view = {
        NULL
 };
 
-struct debug_view debug_pages_view = {
+static struct debug_view debug_pages_view = {
        "pages",
        &debug_prolog_pages_fn,
        NULL,
@@ -138,7 +138,7 @@ struct debug_view debug_pages_view = {
        NULL
 };
 
-struct debug_view debug_flush_view = {
+static struct debug_view debug_flush_view = {
         "flush",
         NULL,
         NULL,
@@ -156,14 +156,14 @@ struct debug_view debug_sprintf_view = {
        NULL
 };
 
-
+/* used by dump analysis tools to determine version of debug feature */
 unsigned int debug_feature_version = __DEBUG_FEATURE_VERSION;
 
 /* static globals */
 
 static debug_info_t *debug_area_first = NULL;
 static debug_info_t *debug_area_last = NULL;
-DECLARE_MUTEX(debug_lock);
+static DECLARE_MUTEX(debug_lock);
 
 static int initialized;
 
@@ -905,7 +905,7 @@ static struct ctl_table s390dbf_dir_table[] = {
        { .ctl_name = 0 }
 };
 
-struct ctl_table_header *s390dbf_sysctl_header;
+static struct ctl_table_header *s390dbf_sysctl_header;
 
 void
 debug_stop_all(void)
@@ -1300,8 +1300,7 @@ out:
  * flushes debug areas
  */
  
-void
-debug_flush(debug_info_t* id, int area)
+static void debug_flush(debug_info_t* id, int area)
 {
         unsigned long flags;
         int i,j;
@@ -1511,8 +1510,7 @@ out:
 /*
  * clean up module
  */
-void
-__exit debug_exit(void)
+static void __exit debug_exit(void)
 {
        debugfs_remove(debug_debugfs_root_entry);
        unregister_sysctl_table(s390dbf_sysctl_header);
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
new file mode 100644 (file)
index 0000000..e518dd5
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ *  arch/s390/kernel/early.c
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Hongjie Yang <hongjie@us.ibm.com>,
+ *              Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/pfn.h>
+#include <linux/uaccess.h>
+#include <asm/lowcore.h>
+#include <asm/processor.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/cpcmd.h>
+#include <asm/sclp.h>
+
+/*
+ * Create a Kernel NSS if the SAVESYS= parameter is defined
+ */
+#define DEFSYS_CMD_SIZE                96
+#define SAVESYS_CMD_SIZE       32
+
+char kernel_nss_name[NSS_NAME_SIZE + 1];
+
+#ifdef CONFIG_SHARED_KERNEL
+static noinline __init void create_kernel_nss(void)
+{
+       unsigned int i, stext_pfn, eshared_pfn, end_pfn, min_size;
+#ifdef CONFIG_BLK_DEV_INITRD
+       unsigned int sinitrd_pfn, einitrd_pfn;
+#endif
+       int response;
+       char *savesys_ptr;
+       char upper_command_line[COMMAND_LINE_SIZE];
+       char defsys_cmd[DEFSYS_CMD_SIZE];
+       char savesys_cmd[SAVESYS_CMD_SIZE];
+
+       /* Do nothing if we are not running under VM */
+       if (!MACHINE_IS_VM)
+               return;
+
+       /* Convert COMMAND_LINE to upper case */
+       for (i = 0; i < strlen(COMMAND_LINE); i++)
+               upper_command_line[i] = toupper(COMMAND_LINE[i]);
+
+       savesys_ptr = strstr(upper_command_line, "SAVESYS=");
+
+       if (!savesys_ptr)
+               return;
+
+       savesys_ptr += 8;    /* Point to the beginning of the NSS name */
+       for (i = 0; i < NSS_NAME_SIZE; i++) {
+               if (savesys_ptr[i] == ' ' || savesys_ptr[i] == '\0')
+                       break;
+               kernel_nss_name[i] = savesys_ptr[i];
+       }
+
+       stext_pfn = PFN_DOWN(__pa(&_stext));
+       eshared_pfn = PFN_DOWN(__pa(&_eshared));
+       end_pfn = PFN_UP(__pa(&_end));
+       min_size = end_pfn << 2;
+
+       sprintf(defsys_cmd, "DEFSYS %s 00000-%.5X EW %.5X-%.5X SR %.5X-%.5X",
+               kernel_nss_name, stext_pfn - 1, stext_pfn, eshared_pfn - 1,
+               eshared_pfn, end_pfn);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+       if (INITRD_START && INITRD_SIZE) {
+               sinitrd_pfn = PFN_DOWN(__pa(INITRD_START));
+               einitrd_pfn = PFN_UP(__pa(INITRD_START + INITRD_SIZE));
+               min_size = einitrd_pfn << 2;
+               sprintf(defsys_cmd, "%s EW %.5X-%.5X", defsys_cmd,
+               sinitrd_pfn, einitrd_pfn);
+       }
+#endif
+
+       sprintf(defsys_cmd, "%s EW MINSIZE=%.7iK", defsys_cmd, min_size);
+       sprintf(savesys_cmd, "SAVESYS %s \n IPL %s",
+               kernel_nss_name, kernel_nss_name);
+
+       __cpcmd(defsys_cmd, NULL, 0, &response);
+
+       if (response != 0)
+               return;
+
+       __cpcmd(savesys_cmd, NULL, 0, &response);
+
+       if (response != strlen(savesys_cmd))
+               return;
+
+       ipl_flags = IPL_NSS_VALID;
+}
+
+#else /* CONFIG_SHARED_KERNEL */
+
+static inline void create_kernel_nss(void) { }
+
+#endif /* CONFIG_SHARED_KERNEL */
+
+/*
+ * Clear bss memory
+ */
+static noinline __init void clear_bss_section(void)
+{
+       memset(__bss_start, 0, _end - __bss_start);
+}
+
+/*
+ * Initialize storage key for kernel pages
+ */
+static noinline __init void init_kernel_storage_key(void)
+{
+       unsigned long end_pfn, init_pfn;
+
+       end_pfn = PFN_UP(__pa(&_end));
+
+       for (init_pfn = 0 ; init_pfn < end_pfn; init_pfn++)
+               page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
+}
+
+static noinline __init void detect_machine_type(void)
+{
+       struct cpuinfo_S390 *cpuinfo = &S390_lowcore.cpu_data;
+
+       asm volatile("stidp %0" : "=m" (S390_lowcore.cpu_data.cpu_id));
+
+       /* Running under z/VM ? */
+       if (cpuinfo->cpu_id.version == 0xff)
+               machine_flags |= 1;
+
+       /* Running on a P/390 ? */
+       if (cpuinfo->cpu_id.machine == 0x7490)
+               machine_flags |= 4;
+}
+
+static noinline __init int memory_fast_detect(void)
+{
+
+       unsigned long val0 = 0;
+       unsigned long val1 = 0xc;
+       int ret = -ENOSYS;
+
+       if (ipl_flags & IPL_NSS_VALID)
+               return -ENOSYS;
+
+       asm volatile(
+               "       diag    %1,%2,0x260\n"
+               "0:     lhi     %0,0\n"
+               "1:\n"
+               EX_TABLE(0b,1b)
+               : "+d" (ret), "+d" (val0), "+d" (val1) : : "cc");
+
+       if (ret || val0 != val1)
+               return -ENOSYS;
+
+       memory_chunk[0].size = val0;
+       return 0;
+}
+
+#define ADDR2G (1UL << 31)
+
+static noinline __init unsigned long sclp_memory_detect(void)
+{
+       struct sclp_readinfo_sccb *sccb;
+       unsigned long long memsize;
+
+       sccb = &s390_readinfo_sccb;
+
+       if (sccb->header.response_code != 0x10)
+               return 0;
+
+       if (sccb->rnsize)
+               memsize = sccb->rnsize << 20;
+       else
+               memsize = sccb->rnsize2 << 20;
+       if (sccb->rnmax)
+               memsize *= sccb->rnmax;
+       else
+               memsize *= sccb->rnmax2;
+#ifndef CONFIG_64BIT
+       /*
+        * Can't deal with more than 2G in 31 bit addressing mode, so
+        * limit the value in order to avoid strange side effects.
+        */
+       if (memsize > ADDR2G)
+               memsize = ADDR2G;
+#endif
+       return (unsigned long) memsize;
+}
+
+static inline __init unsigned long __tprot(unsigned long addr)
+{
+       int cc = -1;
+
+       asm volatile(
+               "       tprot   0(%1),0\n"
+               "0:     ipm     %0\n"
+               "       srl     %0,28\n"
+               "1:\n"
+               EX_TABLE(0b,1b)
+               : "+d" (cc) : "a" (addr) : "cc");
+       return (unsigned long)cc;
+}
+
+/* Checking memory in 128KB increments. */
+#define CHUNK_INCR     (1UL << 17)
+
+static noinline __init void find_memory_chunks(unsigned long memsize)
+{
+       unsigned long addr = 0, old_addr = 0;
+       unsigned long old_cc = CHUNK_READ_WRITE;
+       unsigned long cc;
+       int chunk = 0;
+
+       while (chunk < MEMORY_CHUNKS) {
+               cc = __tprot(addr);
+               while (cc == old_cc) {
+                       addr += CHUNK_INCR;
+                       cc = __tprot(addr);
+#ifndef CONFIG_64BIT
+                       if (addr == ADDR2G)
+                               break;
+#endif
+               }
+
+               if (old_addr != addr &&
+                   (old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) {
+                       memory_chunk[chunk].addr = old_addr;
+                       memory_chunk[chunk].size = addr - old_addr;
+                       memory_chunk[chunk].type = old_cc;
+                       chunk++;
+               }
+
+               old_addr = addr;
+               old_cc = cc;
+
+#ifndef CONFIG_64BIT
+               if (addr == ADDR2G)
+                       break;
+#endif
+               /*
+                * Finish memory detection at the first hole, unless
+                * - we reached the hsa -> skip it.
+                * - we know there must be more.
+                */
+               if (cc == -1UL && !memsize && old_addr != ADDR2G)
+                       break;
+               if (memsize && addr >= memsize)
+                       break;
+       }
+}
+
+static __init void early_pgm_check_handler(void)
+{
+       unsigned long addr;
+       const struct exception_table_entry *fixup;
+
+       addr = S390_lowcore.program_old_psw.addr;
+       fixup = search_exception_tables(addr & PSW_ADDR_INSN);
+       if (!fixup)
+               disabled_wait(0);
+       S390_lowcore.program_old_psw.addr = fixup->fixup | PSW_ADDR_AMODE;
+}
+
+static noinline __init void setup_lowcore_early(void)
+{
+       psw_t psw;
+
+       psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
+       psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_ext_handler;
+       S390_lowcore.external_new_psw = psw;
+       psw.addr = PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
+       S390_lowcore.program_new_psw = psw;
+       s390_base_pgm_handler_fn = early_pgm_check_handler;
+}
+
+/*
+ * Save ipl parameters, clear bss memory, initialize storage keys
+ * and create a kernel NSS at startup if the SAVESYS= parm is defined
+ */
+void __init startup_init(void)
+{
+       unsigned long memsize;
+
+       ipl_save_parameters();
+       clear_bss_section();
+       init_kernel_storage_key();
+       lockdep_init();
+       lockdep_off();
+       detect_machine_type();
+       create_kernel_nss();
+       sort_main_extable();
+       setup_lowcore_early();
+       sclp_readinfo_early();
+       memsize = sclp_memory_detect();
+       if (memory_fast_detect() < 0)
+               find_memory_chunks(memsize);
+       lockdep_on();
+}
index bb0f973..cc0dc60 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/module.h>
 #include <asm/types.h>
+#include <asm/ebcdic.h>
 
 /*
  * ASCII (IBM PC 437)  -> EBCDIC 037
index eca5070..453fd3b 100644 (file)
@@ -51,175 +51,14 @@ startup_continue:
        st      %r15,__LC_KERNEL_STACK  # set end of kernel stack
        ahi     %r15,-96
        xc      __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
-
-       l       %r14,.Lipl_save_parameters-.LPG1(%r13)
-       basr    %r14,%r14
 #
-# clear bss memory
+# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
+# and create a kernel NSS if the SAVESYS= parm is defined
 #
-       l       %r2,.Lbss_bgn-.LPG1(%r13) # start of bss
-       l       %r3,.Lbss_end-.LPG1(%r13) # end of bss
-       sr      %r3,%r2                 # length of bss
-       sr      %r4,%r4
-       sr      %r5,%r5                 # set src,length and pad to zero
-       sr      %r0,%r0
-       mvcle   %r2,%r4,0               # clear mem
-       jo      .-4                     # branch back, if not finish
-
-       l       %r2,.Lrcp-.LPG1(%r13)   # Read SCP forced command word
-.Lservicecall:
-       stosm   .Lpmask-.LPG1(%r13),0x01        # authorize ext interrupts
-
-       stctl   %r0, %r0,.Lcr-.LPG1(%r13)       # get cr0
-       la      %r1,0x200               # set bit 22
-       o       %r1,.Lcr-.LPG1(%r13)    # or old cr0 with r1
-       st      %r1,.Lcr-.LPG1(%r13)
-       lctl    %r0, %r0,.Lcr-.LPG1(%r13)       # load modified cr0
-
-       mvc     __LC_EXT_NEW_PSW(8),.Lpcext-.LPG1(%r13) # set postcall psw
-       la      %r1, .Lsclph-.LPG1(%r13)
-       a       %r1,__LC_EXT_NEW_PSW+4  # set handler
-       st      %r1,__LC_EXT_NEW_PSW+4
-
-       l       %r4,.Lsccbaddr-.LPG1(%r13) # %r4 is our index for sccb stuff
-       lr      %r1,%r4                 # our sccb
-       .insn   rre,0xb2200000,%r2,%r1  # service call
-       ipm     %r1
-       srl     %r1,28                  # get cc code
-       xr      %r3, %r3
-       chi     %r1,3
-       be      .Lfchunk-.LPG1(%r13)    # leave
-       chi     %r1,2
-       be      .Lservicecall-.LPG1(%r13)
-       lpsw    .Lwaitsclp-.LPG1(%r13)
-.Lsclph:
-       lh      %r1,.Lsccbr-.Lsccb(%r4)
-       chi     %r1,0x10                # 0x0010 is the sucess code
-       je      .Lprocsccb              # let's process the sccb
-       chi     %r1,0x1f0
-       bne     .Lfchunk-.LPG1(%r13)    # unhandled error code
-       c       %r2, .Lrcp-.LPG1(%r13)  # Did we try Read SCP forced
-       bne     .Lfchunk-.LPG1(%r13)    # if no, give up
-       l       %r2, .Lrcp2-.LPG1(%r13) # try with Read SCP
-       b       .Lservicecall-.LPG1(%r13)
-.Lprocsccb:
-       lhi     %r1,0
-       icm     %r1,3,.Lscpincr1-.Lsccb(%r4) # use this one if != 0
-       jnz     .Lscnd
-       lhi     %r1,0x800               # otherwise report 2GB
-.Lscnd:
-       lhi     %r3,0x800               # limit reported memory size to 2GB
-       cr      %r1,%r3
-       jl      .Lno2gb
-       lr      %r1,%r3
-.Lno2gb:
-       xr      %r3,%r3                 # same logic
-       ic      %r3,.Lscpa1-.Lsccb(%r4)
-       chi     %r3,0x00
-       jne     .Lcompmem
-       l       %r3,.Lscpa2-.Lsccb(%r4)
-.Lcompmem:
-       mr      %r2,%r1                 # mem in MB on 128-bit
-       l       %r1,.Lonemb-.LPG1(%r13)
-       mr      %r2,%r1                 # mem size in bytes in %r3
-       b       .Lfchunk-.LPG1(%r13)
-
-       .align 4
-.Lipl_save_parameters:
-       .long   ipl_save_parameters
-.Linittu:
-       .long   init_thread_union
-.Lpmask:
-       .byte   0
-       .align  8
-.Lpcext:.long  0x00080000,0x80000000
-.Lcr:
-       .long   0x00                    # place holder for cr0
-       .align  8
-.Lwaitsclp:
-       .long 0x010a0000,0x80000000 + .Lsclph
-.Lrcp:
-       .int    0x00120001              # Read SCP forced code
-.Lrcp2:
-       .int    0x00020001              # Read SCP code
-.Lonemb:
-       .int    0x100000
-.Lfchunk:
+       l       %r14,.Lstartup_init-.LPG1(%r13)
+       basr    %r14,%r14
 
-#
-# find memory chunks.
-#
-       lr      %r9,%r3                 # end of mem
-       mvc     __LC_PGM_NEW_PSW(8),.Lpcmem-.LPG1(%r13)
-       la      %r1,1                   # test in increments of 128KB
-       sll     %r1,17
-       l       %r3,.Lmchunk-.LPG1(%r13) # get pointer to memory_chunk array
-       slr     %r4,%r4                 # set start of chunk to zero
-       slr     %r5,%r5                 # set end of chunk to zero
-       slr     %r6,%r6                 # set access code to zero
-       la      %r10,MEMORY_CHUNKS      # number of chunks
-.Lloop:
-       tprot   0(%r5),0                # test protection of first byte
-       ipm     %r7
-       srl     %r7,28
-       clr     %r6,%r7                 # compare cc with last access code
-       be      .Lsame-.LPG1(%r13)
-       lhi     %r8,0                   # no program checks
-       b       .Lsavchk-.LPG1(%r13)
-.Lsame:
-       ar      %r5,%r1                 # add 128KB to end of chunk
-       bno     .Lloop-.LPG1(%r13)      # r1 < 0x80000000 -> loop
-.Lchkmem:                              # > 2GB or tprot got a program check
-       lhi     %r8,1                   # set program check flag
-.Lsavchk:
-       clr     %r4,%r5                 # chunk size > 0?
-       be      .Lchkloop-.LPG1(%r13)
-       st      %r4,0(%r3)              # store start address of chunk
-       lr      %r0,%r5
-       slr     %r0,%r4
-       st      %r0,4(%r3)              # store size of chunk
-       st      %r6,8(%r3)              # store type of chunk
-       la      %r3,12(%r3)
-       ahi     %r10,-1                 # update chunk number
-.Lchkloop:
-       lr      %r6,%r7                 # set access code to last cc
-       # we got an exception or we're starting a new
-       # chunk , we must check if we should
-       # still try to find valid memory (if we detected
-       # the amount of available storage), and if we
-       # have chunks left
-       xr      %r0,%r0
-       clr     %r0,%r9                 # did we detect memory?
-       je      .Ldonemem               # if not, leave
-       chi     %r10,0                  # do we have chunks left?
-       je      .Ldonemem
-       chi     %r8,1                   # program check ?
-       je      .Lpgmchk
-       lr      %r4,%r5                 # potential new chunk
-       alr     %r5,%r1                 # add 128KB to end of chunk
-       j       .Llpcnt
-.Lpgmchk:
-       alr     %r5,%r1                 # add 128KB to end of chunk
-       lr      %r4,%r5                 # potential new chunk
-.Llpcnt:
-       clr     %r5,%r9                 # should we go on?
-       jl      .Lloop
-.Ldonemem:
        l       %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
-#
-# find out if we are running under VM
-#
-       stidp   __LC_CPUID              # store cpuid
-       tm      __LC_CPUID,0xff         # running under VM ?
-       bno     .Lnovm-.LPG1(%r13)
-       oi      3(%r12),1               # set VM flag
-.Lnovm:
-       lh      %r0,__LC_CPUID+4        # get cpu version
-       chi     %r0,0x7490              # running on a P/390 ?
-       bne     .Lnop390-.LPG1(%r13)
-       oi      3(%r12),4               # set P/390 flag
-.Lnop390:
-
 #
 # find out if we have an IEEE fpu
 #
@@ -295,7 +134,6 @@ startup_continue:
        .long   0                       # cr15: linkage stack operations
 .Lduct:        .long   0,0,0,0,0,0,0,0
        .long   0,0,0,0,0,0,0,0
-.Lpcmem:.long  0x00080000,0x80000000 + .Lchkmem
 .Lpcfpu:.long  0x00080000,0x80000000 + .Lchkfpu
 .Lpccsp:.long  0x00080000,0x80000000 + .Lchkcsp
 .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
@@ -306,7 +144,9 @@ startup_continue:
 .Lbss_bgn:  .long __bss_start
 .Lbss_end:  .long _end
 .Lparmaddr: .long PARMAREA
-.Lsccbaddr: .long .Lsccb
+.Linittu:   .long init_thread_union
+.Lstartup_init:
+           .long startup_init
 
        .globl ipl_schib
 ipl_schib:
@@ -322,26 +162,6 @@ ipl_devno:
        .word 0
 
        .org    0x12000
-.globl s390_readinfo_sccb
-s390_readinfo_sccb:
-.Lsccb:
-       .hword  0x1000                  # length, one page
-       .byte   0x00,0x00,0x00
-       .byte   0x80                    # variable response bit set
-.Lsccbr:
-       .hword  0x00                    # response code
-.Lscpincr1:
-       .hword  0x00
-.Lscpa1:
-       .byte   0x00
-       .fill   89,1,0
-.Lscpa2:
-       .int    0x00
-.Lscpincr2:
-       .quad   0x00
-       .fill   3984,1,0
-       .org    0x13000
-
 #ifdef CONFIG_SHARED_KERNEL
        .org    0x100000
 #endif
index 6ba3f45..b8fec4e 100644 (file)
@@ -58,182 +58,14 @@ startup_continue:
        stg     %r15,__LC_KERNEL_STACK  # set end of kernel stack
        aghi    %r15,-160
        xc      __SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15) # clear backchain
-
-       brasl   %r14,ipl_save_parameters
 #
-# clear bss memory
+# Save ipl parameters, clear bss memory, initialize storage key for kernel pages,
+# and create a kernel NSS if the SAVESYS= parm is defined
 #
-       larl    %r2,__bss_start         # start of bss segment
-       larl    %r3,_end                # end of bss segment
-       sgr     %r3,%r2                 # length of bss
-       sgr     %r4,%r4                 #
-       sgr     %r5,%r5                 # set src,length and pad to zero
-       mvcle   %r2,%r4,0               # clear mem
-       jo      .-4                     # branch back, if not finish
+       brasl   %r14,startup_init
                                        # set program check new psw mask
        mvc     __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
-       larl    %r1,.Lslowmemdetect     # set program check address
-       stg     %r1,__LC_PGM_NEW_PSW+8
-       lghi    %r1,0xc
-       diag    %r0,%r1,0x260           # get memory size of virtual machine
-       cgr     %r0,%r1                 # different? -> old detection routine
-       jne     .Lslowmemdetect
-       aghi    %r1,1                   # size is one more than end
-       larl    %r2,memory_chunk
-       stg     %r1,8(%r2)              # store size of chunk
-       j       .Ldonemem
-
-.Lslowmemdetect:
-       l       %r2,.Lrcp-.LPG1(%r13)   # Read SCP forced command word
-.Lservicecall:
-       stosm   .Lpmask-.LPG1(%r13),0x01        # authorize ext interrupts
-
-       stctg   %r0,%r0,.Lcr-.LPG1(%r13)        # get cr0
-       la      %r1,0x200               # set bit 22
-       og      %r1,.Lcr-.LPG1(%r13)    # or old cr0 with r1
-       stg     %r1,.Lcr-.LPG1(%r13)
-       lctlg   %r0,%r0,.Lcr-.LPG1(%r13)        # load modified cr0
-
-       mvc     __LC_EXT_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) # set postcall psw
-       larl    %r1,.Lsclph
-       stg     %r1,__LC_EXT_NEW_PSW+8  # set handler
-
-       larl    %r4,.Lsccb              # %r4 is our index for sccb stuff
-       lgr     %r1,%r4                 # our sccb
-       .insn   rre,0xb2200000,%r2,%r1  # service call
-       ipm     %r1
-       srl     %r1,28                  # get cc code
-       xr      %r3,%r3
-       chi     %r1,3
-       be      .Lfchunk-.LPG1(%r13)    # leave
-       chi     %r1,2
-       be      .Lservicecall-.LPG1(%r13)
-       lpswe   .Lwaitsclp-.LPG1(%r13)
-.Lsclph:
-       lh      %r1,.Lsccbr-.Lsccb(%r4)
-       chi     %r1,0x10                # 0x0010 is the sucess code
-       je      .Lprocsccb              # let's process the sccb
-       chi     %r1,0x1f0
-       bne     .Lfchunk-.LPG1(%r13)    # unhandled error code
-       c       %r2,.Lrcp-.LPG1(%r13)   # Did we try Read SCP forced
-       bne     .Lfchunk-.LPG1(%r13)    # if no, give up
-       l       %r2,.Lrcp2-.LPG1(%r13)  # try with Read SCP
-       b       .Lservicecall-.LPG1(%r13)
-.Lprocsccb:
-       lghi    %r1,0
-       icm     %r1,3,.Lscpincr1-.Lsccb(%r4)    # use this one if != 0
-       jnz     .Lscnd
-       lg      %r1,.Lscpincr2-.Lsccb(%r4)      # otherwise use this one
-.Lscnd:
-       xr      %r3,%r3                 # same logic
-       ic      %r3,.Lscpa1-.Lsccb(%r4)
-       chi     %r3,0x00
-       jne     .Lcompmem
-       l       %r3,.Lscpa2-.Lsccb(%r4)
-.Lcompmem:
-       mlgr    %r2,%r1                 # mem in MB on 128-bit
-       l       %r1,.Lonemb-.LPG1(%r13)
-       mlgr    %r2,%r1                 # mem size in bytes in %r3
-       b       .Lfchunk-.LPG1(%r13)
-
-       .align  4
-.Lpmask:
-       .byte   0
-       .align  8
-.Lcr:
-       .quad   0x00  # place holder for cr0
-.Lwaitsclp:
-       .quad   0x0102000180000000,.Lsclph
-.Lrcp:
-       .int    0x00120001 # Read SCP forced code
-.Lrcp2:
-       .int    0x00020001 # Read SCP code
-.Lonemb:
-       .int    0x100000
-
-.Lfchunk:
-
-#
-# find memory chunks.
-#
-       lgr     %r9,%r3                 # end of mem
-       larl    %r1,.Lchkmem            # set program check address
-       stg     %r1,__LC_PGM_NEW_PSW+8
-       la      %r1,1                   # test in increments of 128KB
-       sllg    %r1,%r1,17
-       larl    %r3,memory_chunk
-       slgr    %r4,%r4                 # set start of chunk to zero
-       slgr    %r5,%r5                 # set end of chunk to zero
-       slr     %r6,%r6                 # set access code to zero
-       la      %r10,MEMORY_CHUNKS      # number of chunks
-.Lloop:
-       tprot   0(%r5),0                # test protection of first byte
-       ipm     %r7
-       srl     %r7,28
-       clr     %r6,%r7                 # compare cc with last access code
-       je      .Lsame
-       lghi    %r8,0                   # no program checks
-       j       .Lsavchk
-.Lsame:
-       algr    %r5,%r1                 # add 128KB to end of chunk
-                                       # no need to check here,
-       brc     12,.Lloop               # this is the same chunk
-.Lchkmem:                              # > 16EB or tprot got a program check
-       lghi    %r8,1                   # set program check flag
-.Lsavchk:
-       clgr    %r4,%r5                 # chunk size > 0?
-       je      .Lchkloop
-       stg     %r4,0(%r3)              # store start address of chunk
-       lgr     %r0,%r5
-       slgr    %r0,%r4
-       stg     %r0,8(%r3)              # store size of chunk
-       st      %r6,20(%r3)             # store type of chunk
-       la      %r3,24(%r3)
-       ahi     %r10,-1                 # update chunk number
-.Lchkloop:
-       lr      %r6,%r7                 # set access code to last cc
-       # we got an exception or we're starting a new
-       # chunk , we must check if we should
-       # still try to find valid memory (if we detected
-       # the amount of available storage), and if we
-       # have chunks left
-       lghi    %r4,1
-       sllg    %r4,%r4,31
-       clgr    %r5,%r4
-       je      .Lhsaskip
-       xr      %r0, %r0
-       clgr    %r0, %r9                # did we detect memory?
-       je      .Ldonemem               # if not, leave
-       chi     %r10, 0                 # do we have chunks left?
-       je      .Ldonemem
-.Lhsaskip:
-       chi     %r8,1                   # program check ?
-       je      .Lpgmchk
-       lgr     %r4,%r5                 # potential new chunk
-       algr    %r5,%r1                 # add 128KB to end of chunk
-       j       .Llpcnt
-.Lpgmchk:
-       algr    %r5,%r1                 # add 128KB to end of chunk
-       lgr     %r4,%r5                 # potential new chunk
-.Llpcnt:
-       clgr    %r5,%r9                 # should we go on?
-       jl      .Lloop
-.Ldonemem:
-
        larl    %r12,machine_flags
-#
-# find out if we are running under VM
-#
-       stidp   __LC_CPUID              # store cpuid
-       tm      __LC_CPUID,0xff         # running under VM ?
-       bno     0f-.LPG1(%r13)
-       oi      7(%r12),1               # set VM flag
-0:     lh      %r0,__LC_CPUID+4        # get cpu version
-       chi     %r0,0x7490              # running on a P/390 ?
-       bne     1f-.LPG1(%r13)
-       oi      7(%r12),4               # set P/390 flag
-1:
-
 #
 # find out if we have the MVPG instruction
 #
@@ -336,25 +168,6 @@ ipl_devno:
        .word 0
 
        .org    0x12000
-.globl s390_readinfo_sccb
-s390_readinfo_sccb:
-.Lsccb:
-       .hword  0x1000                  # length, one page
-       .byte   0x00,0x00,0x00
-       .byte   0x80                    # variable response bit set
-.Lsccbr:
-       .hword  0x00                    # response code
-.Lscpincr1:
-       .hword  0x00
-.Lscpa1:
-       .byte   0x00
-       .fill   89,1,0
-.Lscpa2:
-       .int    0x00
-.Lscpincr2:
-       .quad   0x00
-       .fill   3984,1,0
-       .org    0x13000
 
 #ifdef CONFIG_SHARED_KERNEL
        .org    0x100000
index 9e9972e..0522595 100644 (file)
 #include <asm/cio.h>
 #include <asm/ebcdic.h>
 #include <asm/reset.h>
+#include <asm/sclp.h>
 
 #define IPL_PARM_BLOCK_VERSION 0
-#define LOADPARM_LEN 8
 
-extern char s390_readinfo_sccb[];
-#define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010)
-#define SCCB_LOADPARM (&s390_readinfo_sccb[24])
-#define SCCB_FLAG (s390_readinfo_sccb[91])
+#define SCCB_VALID (s390_readinfo_sccb.header.response_code == 0x10)
+#define SCCB_LOADPARM (&s390_readinfo_sccb.loadparm)
+#define SCCB_FLAG (s390_readinfo_sccb.flags)
 
 enum ipl_type {
        IPL_TYPE_NONE    = 1,
        IPL_TYPE_UNKNOWN = 2,
        IPL_TYPE_CCW     = 4,
        IPL_TYPE_FCP     = 8,
+       IPL_TYPE_NSS     = 16,
 };
 
 #define IPL_NONE_STR    "none"
 #define IPL_UNKNOWN_STR  "unknown"
 #define IPL_CCW_STR     "ccw"
 #define IPL_FCP_STR     "fcp"
+#define IPL_NSS_STR     "nss"
 
 static char *ipl_type_str(enum ipl_type type)
 {
@@ -50,6 +51,8 @@ static char *ipl_type_str(enum ipl_type type)
                return IPL_CCW_STR;
        case IPL_TYPE_FCP:
                return IPL_FCP_STR;
+       case IPL_TYPE_NSS:
+               return IPL_NSS_STR;
        case IPL_TYPE_UNKNOWN:
        default:
                return IPL_UNKNOWN_STR;
@@ -64,6 +67,7 @@ enum ipl_method {
        IPL_METHOD_FCP_RO_DIAG,
        IPL_METHOD_FCP_RW_DIAG,
        IPL_METHOD_FCP_RO_VM,
+       IPL_METHOD_NSS,
 };
 
 enum shutdown_action {
@@ -114,11 +118,14 @@ enum diag308_rc {
 static int diag308_set_works = 0;
 
 static int reipl_capabilities = IPL_TYPE_UNKNOWN;
+
 static enum ipl_type reipl_type = IPL_TYPE_UNKNOWN;
 static enum ipl_method reipl_method = IPL_METHOD_NONE;
 static struct ipl_parameter_block *reipl_block_fcp;
 static struct ipl_parameter_block *reipl_block_ccw;
 
+static char reipl_nss_name[NSS_NAME_SIZE + 1];
+
 static int dump_capabilities = IPL_TYPE_NONE;
 static enum ipl_type dump_type = IPL_TYPE_NONE;
 static enum ipl_method dump_method = IPL_METHOD_NONE;
@@ -173,6 +180,24 @@ static struct subsys_attribute sys_##_prefix##_##_name##_attr =            \
                        sys_##_prefix##_##_name##_show,                 \
                        sys_##_prefix##_##_name##_store);
 
+#define DEFINE_IPL_ATTR_STR_RW(_prefix, _name, _fmt_out, _fmt_in, _value)\
+static ssize_t sys_##_prefix##_##_name##_show(struct subsystem *subsys,        \
+               char *page)                                             \
+{                                                                      \
+       return sprintf(page, _fmt_out, _value);                         \
+}                                                                      \
+static ssize_t sys_##_prefix##_##_name##_store(struct subsystem *subsys,\
+               const char *buf, size_t len)                            \
+{                                                                      \
+       if (sscanf(buf, _fmt_in, _value) != 1)                          \
+               return -EINVAL;                                         \
+       return len;                                                     \
+}                                                                      \
+static struct subsys_attribute sys_##_prefix##_##_name##_attr =                \
+       __ATTR(_name,(S_IRUGO | S_IWUSR),                               \
+                       sys_##_prefix##_##_name##_show,                 \
+                       sys_##_prefix##_##_name##_store);
+
 static void make_attrs_ro(struct attribute **attrs)
 {
        while (*attrs) {
@@ -189,6 +214,8 @@ static enum ipl_type ipl_get_type(void)
 {
        struct ipl_parameter_block *ipl = IPL_PARMBLOCK_START;
 
+       if (ipl_flags & IPL_NSS_VALID)
+               return IPL_TYPE_NSS;
        if (!(ipl_flags & IPL_DEVNO_VALID))
                return IPL_TYPE_UNKNOWN;
        if (!(ipl_flags & IPL_PARMBLOCK_VALID))
@@ -324,6 +351,20 @@ static struct attribute_group ipl_ccw_attr_group = {
        .attrs = ipl_ccw_attrs,
 };
 
+/* NSS ipl device attributes */
+
+DEFINE_IPL_ATTR_RO(ipl_nss, name, "%s\n", kernel_nss_name);
+
+static struct attribute *ipl_nss_attrs[] = {
+       &sys_ipl_type_attr.attr,
+       &sys_ipl_nss_name_attr.attr,
+       NULL,
+};
+
+static struct attribute_group ipl_nss_attr_group = {
+       .attrs = ipl_nss_attrs,
+};
+
 /* UNKNOWN ipl device attributes */
 
 static struct attribute *ipl_unknown_attrs[] = {
@@ -432,6 +473,21 @@ static struct attribute_group reipl_ccw_attr_group = {
        .attrs = reipl_ccw_attrs,
 };
 
+
+/* NSS reipl device attributes */
+
+DEFINE_IPL_ATTR_STR_RW(reipl_nss, name, "%s\n", "%s\n", reipl_nss_name);
+
+static struct attribute *reipl_nss_attrs[] = {
+       &sys_reipl_nss_name_attr.attr,
+       NULL,
+};
+
+static struct attribute_group reipl_nss_attr_group = {
+       .name  = IPL_NSS_STR,
+       .attrs = reipl_nss_attrs,
+};
+
 /* reipl type */
 
 static int reipl_set_type(enum ipl_type type)
@@ -454,6 +510,9 @@ static int reipl_set_type(enum ipl_type type)
                else
                        reipl_method = IPL_METHOD_FCP_RO_DIAG;
                break;
+       case IPL_TYPE_NSS:
+               reipl_method = IPL_METHOD_NSS;
+               break;
        default:
                reipl_method = IPL_METHOD_NONE;
        }
@@ -475,6 +534,8 @@ static ssize_t reipl_type_store(struct subsystem *subsys, const char *buf,
                rc = reipl_set_type(IPL_TYPE_CCW);
        else if (strncmp(buf, IPL_FCP_STR, strlen(IPL_FCP_STR)) == 0)
                rc = reipl_set_type(IPL_TYPE_FCP);
+       else if (strncmp(buf, IPL_NSS_STR, strlen(IPL_NSS_STR)) == 0)
+               rc = reipl_set_type(IPL_TYPE_NSS);
        return (rc != 0) ? rc : len;
 }
 
@@ -647,6 +708,10 @@ void do_reipl(void)
        case IPL_METHOD_FCP_RO_VM:
                __cpcmd("IPL", NULL, 0, NULL);
                break;
+       case IPL_METHOD_NSS:
+               sprintf(buf, "IPL %s", reipl_nss_name);
+               __cpcmd(buf, NULL, 0, NULL);
+               break;
        case IPL_METHOD_NONE:
        default:
                if (MACHINE_IS_VM)
@@ -733,6 +798,10 @@ static int __init ipl_init(void)
        case IPL_TYPE_FCP:
                rc = ipl_register_fcp_files();
                break;
+       case IPL_TYPE_NSS:
+               rc = sysfs_create_group(&ipl_subsys.kset.kobj,
+                                       &ipl_nss_attr_group);
+               break;
        default:
                rc = sysfs_create_group(&ipl_subsys.kset.kobj,
                                        &ipl_unknown_attr_group);
@@ -755,6 +824,20 @@ static void __init reipl_probe(void)
        free_page((unsigned long)buffer);
 }
 
+static int __init reipl_nss_init(void)
+{
+       int rc;
+
+       if (!MACHINE_IS_VM)
+               return 0;
+       rc = sysfs_create_group(&reipl_subsys.kset.kobj, &reipl_nss_attr_group);
+       if (rc)
+               return rc;
+       strncpy(reipl_nss_name, kernel_nss_name, NSS_NAME_SIZE + 1);
+       reipl_capabilities |= IPL_TYPE_NSS;
+       return 0;
+}
+
 static int __init reipl_ccw_init(void)
 {
        int rc;
@@ -835,6 +918,9 @@ static int __init reipl_init(void)
        if (rc)
                return rc;
        rc = reipl_fcp_init();
+       if (rc)
+               return rc;
+       rc = reipl_nss_init();
        if (rc)
                return rc;
        rc = reipl_set_type(ipl_get_type());
@@ -993,8 +1079,6 @@ static void do_reset_calls(void)
                reset->fn();
 }
 
-extern void reset_mcck_handler(void);
-extern void reset_pgm_handler(void);
 extern __u32 dump_prefix_page;
 
 void s390_reset_system(void)
@@ -1016,14 +1100,14 @@ void s390_reset_system(void)
        __ctl_clear_bit(0,28);
 
        /* Set new machine check handler */
-       S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
+       S390_lowcore.mcck_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
        S390_lowcore.mcck_new_psw.addr =
-               PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler;
+               PSW_ADDR_AMODE | (unsigned long) s390_base_mcck_handler;
 
        /* Set new program check handler */
-       S390_lowcore.program_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK;
+       S390_lowcore.program_new_psw.mask = psw_kernel_bits & ~PSW_MASK_MCHECK;
        S390_lowcore.program_new_psw.addr =
-               PSW_ADDR_AMODE | (unsigned long) &reset_pgm_handler;
+               PSW_ADDR_AMODE | (unsigned long) s390_base_pgm_handler;
 
        do_reset_calls();
 }
index 1eef509..8f0cbca 100644 (file)
@@ -1,9 +1,9 @@
 /*
  *  arch/s390/kernel/irq.c
  *
- *  S390 version
- *    Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 2004,2007
  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *              Thomas Spatzier (tspat@de.ibm.com)
  *
  * This file contains interrupt related functions.
  */
@@ -14,6 +14,8 @@
 #include <linux/interrupt.h>
 #include <linux/seq_file.h>
 #include <linux/cpu.h>
+#include <linux/proc_fs.h>
+#include <linux/profile.h>
 
 /*
  * show_interrupts is needed by /proc/interrupts.
@@ -93,5 +95,12 @@ asmlinkage void do_softirq(void)
 
        local_irq_restore(flags);
 }
-
 EXPORT_SYMBOL(do_softirq);
+
+void init_irq_proc(void)
+{
+       struct proc_dir_entry *root_irq_dir;
+
+       root_irq_dir = proc_mkdir("irq", NULL);
+       create_prof_cpu_mask(root_irq_dir);
+}
index 576368c..a466bab 100644 (file)
@@ -155,15 +155,34 @@ void __kprobes get_instruction_type(struct arch_specific_insn *ainsn)
 static int __kprobes swap_instruction(void *aref)
 {
        struct ins_replace_args *args = aref;
+       u32 *addr;
+       u32 instr;
        int err = -EFAULT;
 
+       /*
+        * Text segment is read-only, hence we use stura to bypass dynamic
+        * address translation to exchange the instruction. Since stura
+        * always operates on four bytes, but we only want to exchange two
+        * bytes do some calculations to get things right. In addition we
+        * shall not cross any page boundaries (vmalloc area!) when writing
+        * the new instruction.
+        */
+       addr = (u32 *)ALIGN((unsigned long)args->ptr, 4);
+       if ((unsigned long)args->ptr & 2)
+               instr = ((*addr) & 0xffff0000) | args->new;
+       else
+               instr = ((*addr) & 0x0000ffff) | args->new << 16;
+
        asm volatile(
-               "0: mvc  0(2,%2),0(%3)\n"
-               "1: la   %0,0\n"
+               "       lra     %1,0(%1)\n"
+               "0:     stura   %2,%1\n"
+               "1:     la      %0,0\n"
                "2:\n"
                EX_TABLE(0b,2b)
-               : "+d" (err), "=m" (*args->ptr)
-               : "a" (args->ptr), "a" (&args->new), "m" (args->new));
+               : "+d" (err)
+               : "a" (addr), "d" (instr)
+               : "memory", "cc");
+
        return err;
 }
 
@@ -356,7 +375,7 @@ no_kprobe:
  *     - When the probed function returns, this probe
  *             causes the handlers to fire
  */
-void __kprobes kretprobe_trampoline_holder(void)
+void kretprobe_trampoline_holder(void)
 {
        asm volatile(".global kretprobe_trampoline\n"
                     "kretprobe_trampoline: bcr 0,0\n");
@@ -365,7 +384,8 @@ void __kprobes kretprobe_trampoline_holder(void)
 /*
  * Called when the probe at kretprobe trampoline is hit
  */
-int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+static int __kprobes trampoline_probe_handler(struct kprobe *p,
+                                             struct pt_regs *regs)
 {
        struct kretprobe_instance *ri = NULL;
        struct hlist_head *head, empty_rp;
index f6d9bcc..52f57af 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/mm.h>
 #include <linux/kexec.h>
 #include <linux/delay.h>
+#include <linux/reboot.h>
 #include <asm/cio.h>
 #include <asm/setup.h>
 #include <asm/pgtable.h>
index d989ed4..39d1dd7 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/fs.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/moduleloader.h>
 
 #if 0
 #define DEBUGP printk
@@ -58,7 +59,7 @@ void module_free(struct module *mod, void *module_region)
            table entries. */
 }
 
-static inline void
+static void
 check_rela(Elf_Rela *rela, struct module *me)
 {
        struct mod_arch_syminfo *info;
@@ -181,7 +182,7 @@ apply_relocate(Elf_Shdr *sechdrs, const char *strtab, unsigned int symindex,
        return -ENOEXEC;
 }
 
-static inline int
+static int
 apply_rela(Elf_Rela *rela, Elf_Addr base, Elf_Sym *symtab, 
           struct module *me)
 {
index 6603fbb..5acfac6 100644 (file)
@@ -144,7 +144,7 @@ static void default_idle(void)
 
        trace_hardirqs_on();
        /* Wait for external, I/O or machine check interrupt. */
-       __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT |
+       __load_psw_mask(psw_kernel_bits | PSW_MASK_WAIT |
                        PSW_MASK_IO | PSW_MASK_EXT);
 }
 
@@ -190,7 +190,7 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
        struct pt_regs regs;
 
        memset(&regs, 0, sizeof(regs));
-       regs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
+       regs.psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
        regs.psw.addr = (unsigned long) kernel_thread_starter | PSW_ADDR_AMODE;
        regs.gprs[9] = (unsigned long) fn;
        regs.gprs[10] = (unsigned long) arg;
diff --git a/arch/s390/kernel/profile.c b/arch/s390/kernel/profile.c
deleted file mode 100644 (file)
index b81aa1f..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * arch/s390/kernel/profile.c
- *
- * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Thomas Spatzier (tspat@de.ibm.com)
- *
- */
-#include <linux/proc_fs.h>
-#include <linux/profile.h>
-
-static struct proc_dir_entry * root_irq_dir;
-
-void init_irq_proc(void)
-{
-       /* create /proc/irq */
-       root_irq_dir = proc_mkdir("irq", NULL);
-
-       /* create /proc/irq/prof_cpu_mask */
-       create_prof_cpu_mask(root_irq_dir);
-}
index 8f36504..2a8f087 100644 (file)
@@ -86,15 +86,13 @@ FixPerRegisters(struct task_struct *task)
                per_info->control_regs.bits.storage_alt_space_ctl = 0;
 }
 
-void
-set_single_step(struct task_struct *task)
+static void set_single_step(struct task_struct *task)
 {
        task->thread.per_info.single_step = 1;
        FixPerRegisters(task);
 }
 
-void
-clear_single_step(struct task_struct *task)
+static void clear_single_step(struct task_struct *task)
 {
        task->thread.per_info.single_step = 0;
        FixPerRegisters(task);
@@ -232,9 +230,9 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
                 */
                if (addr == (addr_t) &dummy->regs.psw.mask &&
 #ifdef CONFIG_COMPAT
-                   data != PSW_MASK_MERGE(PSW_USER32_BITS, data) &&
+                   data != PSW_MASK_MERGE(psw_user32_bits, data) &&
 #endif
-                   data != PSW_MASK_MERGE(PSW_USER_BITS, data))
+                   data != PSW_MASK_MERGE(psw_user_bits, data))
                        /* Invalid psw mask. */
                        return -EINVAL;
 #ifndef CONFIG_64BIT
@@ -309,7 +307,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
                copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
                if (copied != sizeof(tmp))
                        return -EIO;
-               return put_user(tmp, (unsigned long __user *) data);
+               return put_user(tmp, (unsigned long __force __user *) data);
 
        case PTRACE_PEEKUSR:
                /* read the word at location addr in the USER area. */
@@ -331,7 +329,7 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
 
        case PTRACE_PEEKUSR_AREA:
        case PTRACE_POKEUSR_AREA:
-               if (copy_from_user(&parea, (void __user *) addr,
+               if (copy_from_user(&parea, (void __force __user *) addr,
                                                        sizeof(parea)))
                        return -EFAULT;
                addr = parea.kernel_addr;
@@ -341,10 +339,11 @@ do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
                        if (request == PTRACE_PEEKUSR_AREA)
                                ret = peek_user(child, addr, data);
                        else {
-                               addr_t tmp;
-                               if (get_user (tmp, (addr_t __user *) data))
+                               addr_t utmp;
+                               if (get_user(utmp,
+                                            (addr_t __force __user *) data))
                                        return -EFAULT;
-                               ret = poke_user(child, addr, tmp);
+                               ret = poke_user(child, addr, utmp);
                        }
                        if (ret)
                                return ret;
@@ -394,7 +393,7 @@ peek_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
                if (addr == (addr_t) &dummy32->regs.psw.mask) {
                        /* Fake a 31 bit psw mask. */
                        tmp = (__u32)(task_pt_regs(child)->psw.mask >> 32);
-                       tmp = PSW32_MASK_MERGE(PSW32_USER_BITS, tmp);
+                       tmp = PSW32_MASK_MERGE(psw32_user_bits, tmp);
                } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
                        /* Fake a 31 bit psw address. */
                        tmp = (__u32) task_pt_regs(child)->psw.addr |
@@ -469,11 +468,11 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
                 */
                if (addr == (addr_t) &dummy32->regs.psw.mask) {
                        /* Build a 64 bit psw mask from 31 bit mask. */
-                       if (tmp != PSW32_MASK_MERGE(PSW32_USER_BITS, tmp))
+                       if (tmp != PSW32_MASK_MERGE(psw32_user_bits, tmp))
                                /* Invalid psw mask. */
                                return -EINVAL;
                        task_pt_regs(child)->psw.mask =
-                               PSW_MASK_MERGE(PSW_USER32_BITS, (__u64) tmp << 32);
+                               PSW_MASK_MERGE(psw_user32_bits, (__u64) tmp << 32);
                } else if (addr == (addr_t) &dummy32->regs.psw.addr) {
                        /* Build a 64 bit psw address from 31 bit address. */
                        task_pt_regs(child)->psw.addr =
@@ -550,7 +549,7 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
                copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
                if (copied != sizeof(tmp))
                        return -EIO;
-               return put_user(tmp, (unsigned int __user *) data);
+               return put_user(tmp, (unsigned int __force __user *) data);
 
        case PTRACE_PEEKUSR:
                /* read the word at location addr in the USER area. */
@@ -571,7 +570,7 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
 
        case PTRACE_PEEKUSR_AREA:
        case PTRACE_POKEUSR_AREA:
-               if (copy_from_user(&parea, (void __user *) addr,
+               if (copy_from_user(&parea, (void __force __user *) addr,
                                                        sizeof(parea)))
                        return -EFAULT;
                addr = parea.kernel_addr;
@@ -581,10 +580,11 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
                        if (request == PTRACE_PEEKUSR_AREA)
                                ret = peek_user_emu31(child, addr, data);
                        else {
-                               __u32 tmp;
-                               if (get_user (tmp, (__u32 __user *) data))
+                               __u32 utmp;
+                               if (get_user(utmp,
+                                            (__u32 __force __user *) data))
                                        return -EFAULT;
-                               ret = poke_user_emu31(child, addr, tmp);
+                               ret = poke_user_emu31(child, addr, utmp);
                        }
                        if (ret)
                                return ret;
@@ -595,17 +595,19 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
                return 0;
        case PTRACE_GETEVENTMSG:
                return put_user((__u32) child->ptrace_message,
-                               (unsigned int __user *) data);
+                               (unsigned int __force __user *) data);
        case PTRACE_GETSIGINFO:
                if (child->last_siginfo == NULL)
                        return -EINVAL;
-               return copy_siginfo_to_user32((compat_siginfo_t __user *) data,
+               return copy_siginfo_to_user32((compat_siginfo_t
+                                              __force __user *) data,
                                              child->last_siginfo);
        case PTRACE_SETSIGINFO:
                if (child->last_siginfo == NULL)
                        return -EINVAL;
                return copy_siginfo_from_user32(child->last_siginfo,
-                                               (compat_siginfo_t __user *) data);
+                                               (compat_siginfo_t
+                                                __force __user *) data);
        }
        return ptrace_request(child, request, addr, data);
 }
diff --git a/arch/s390/kernel/reset.S b/arch/s390/kernel/reset.S
deleted file mode 100644 (file)
index 8a87355..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- *  arch/s390/kernel/reset.S
- *
- *    Copyright (C) IBM Corp. 2006
- *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
- *              Michael Holzheu <holzheu@de.ibm.com>
- */
-
-#include <asm/ptrace.h>
-#include <asm/lowcore.h>
-
-#ifdef CONFIG_64BIT
-
-       .globl  reset_mcck_handler
-reset_mcck_handler:
-       basr    %r13,0
-0:     lg      %r15,__LC_PANIC_STACK   # load panic stack
-       aghi    %r15,-STACK_FRAME_OVERHEAD
-       lg      %r1,s390_reset_mcck_handler-0b(%r13)
-       ltgr    %r1,%r1
-       jz      1f
-       basr    %r14,%r1
-1:     la      %r1,4095
-       lmg     %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)
-       lpswe   __LC_MCK_OLD_PSW
-
-       .globl  s390_reset_mcck_handler
-s390_reset_mcck_handler:
-       .quad   0
-
-       .globl  reset_pgm_handler
-reset_pgm_handler:
-       stmg    %r0,%r15,__LC_SAVE_AREA
-       basr    %r13,0
-0:     lg      %r15,__LC_PANIC_STACK   # load panic stack
-       aghi    %r15,-STACK_FRAME_OVERHEAD
-       lg      %r1,s390_reset_pgm_handler-0b(%r13)
-       ltgr    %r1,%r1
-       jz      1f
-       basr    %r14,%r1
-       lmg     %r0,%r15,__LC_SAVE_AREA
-       lpswe   __LC_PGM_OLD_PSW
-1:     lpswe   disabled_wait_psw-0b(%r13)
-       .globl s390_reset_pgm_handler
-s390_reset_pgm_handler:
-       .quad   0
-       .align  8
-disabled_wait_psw:
-       .quad   0x0002000180000000,0x0000000000000000 + reset_pgm_handler
-
-#else /* CONFIG_64BIT */
-
-       .globl  reset_mcck_handler
-reset_mcck_handler:
-       basr    %r13,0
-0:     l       %r15,__LC_PANIC_STACK   # load panic stack
-       ahi     %r15,-STACK_FRAME_OVERHEAD
-       l       %r1,s390_reset_mcck_handler-0b(%r13)
-       ltr     %r1,%r1
-       jz      1f
-       basr    %r14,%r1
-1:     lm      %r0,%r15,__LC_GPREGS_SAVE_AREA
-       lpsw    __LC_MCK_OLD_PSW
-
-       .globl  s390_reset_mcck_handler
-s390_reset_mcck_handler:
-       .long   0
-
-       .globl  reset_pgm_handler
-reset_pgm_handler:
-       stm     %r0,%r15,__LC_SAVE_AREA
-       basr    %r13,0
-0:     l       %r15,__LC_PANIC_STACK   # load panic stack
-       ahi     %r15,-STACK_FRAME_OVERHEAD
-       l       %r1,s390_reset_pgm_handler-0b(%r13)
-       ltr     %r1,%r1
-       jz      1f
-       basr    %r14,%r1
-       lm      %r0,%r15,__LC_SAVE_AREA
-       lpsw    __LC_PGM_OLD_PSW
-
-1:     lpsw    disabled_wait_psw-0b(%r13)
-       .globl  s390_reset_pgm_handler
-s390_reset_pgm_handler:
-       .long   0
-disabled_wait_psw:
-       .align 8
-       .long   0x000a0000,0x00000000 + reset_pgm_handler
-
-#endif /* CONFIG_64BIT */
index bc5beaa..acf93db 100644 (file)
@@ -125,14 +125,12 @@ void do_extint(struct pt_regs *regs, unsigned short code)
                 * Make sure that the i/o interrupt did not "overtake"
                 * the last HZ timer interrupt.
                 */
-               account_ticks();
+               account_ticks(S390_lowcore.int_clock);
        kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
         index = ext_hash(code);
        for (p = ext_int_hash[index]; p; p = p->next) {
-               if (likely(p->code == code)) {
-                       if (likely(p->handler))
-                               p->handler(code);
-               }
+               if (likely(p->code == code))
+                       p->handler(code);
        }
        irq_exit();
        set_irq_regs(old_regs);
index 5d8ee3b..0373981 100644 (file)
@@ -38,6 +38,8 @@
 #include <linux/device.h>
 #include <linux/notifier.h>
 #include <linux/pfn.h>
+#include <linux/ctype.h>
+#include <linux/reboot.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
 #include <asm/sections.h>
+#include <asm/ebcdic.h>
+#include <asm/compat.h>
+
+long psw_kernel_bits   = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
+                          PSW_MASK_MCHECK | PSW_DEFAULT_KEY);
+long psw_user_bits     = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+                          PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+                          PSW_MASK_PSTATE | PSW_DEFAULT_KEY);
 
 /*
  * User copy operations.
@@ -117,9 +127,9 @@ void __devinit cpu_init (void)
  */
 char vmhalt_cmd[128] = "";
 char vmpoff_cmd[128] = "";
-char vmpanic_cmd[128] = "";
+static char vmpanic_cmd[128] = "";
 
-static inline void strncpy_skip_quote(char *dst, char *src, int n)
+static void strncpy_skip_quote(char *dst, char *src, int n)
 {
         int sx, dx;
 
@@ -275,10 +285,6 @@ static void __init conmode_default(void)
 }
 
 #ifdef CONFIG_SMP
-extern void machine_restart_smp(char *);
-extern void machine_halt_smp(void);
-extern void machine_power_off_smp(void);
-
 void (*_machine_restart)(char *command) = machine_restart_smp;
 void (*_machine_halt)(void) = machine_halt_smp;
 void (*_machine_power_off)(void) = machine_power_off_smp;
@@ -386,6 +392,84 @@ static int __init early_parse_ipldelay(char *p)
 }
 early_param("ipldelay", early_parse_ipldelay);
 
+#ifdef CONFIG_S390_SWITCH_AMODE
+unsigned int switch_amode = 0;
+EXPORT_SYMBOL_GPL(switch_amode);
+
+static void set_amode_and_uaccess(unsigned long user_amode,
+                                 unsigned long user32_amode)
+{
+       psw_user_bits = PSW_BASE_BITS | PSW_MASK_DAT | user_amode |
+                       PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+                       PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
+#ifdef CONFIG_COMPAT
+       psw_user32_bits = PSW_BASE32_BITS | PSW_MASK_DAT | user_amode |
+                         PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK |
+                         PSW_MASK_PSTATE | PSW_DEFAULT_KEY;
+       psw32_user_bits = PSW32_BASE_BITS | PSW32_MASK_DAT | user32_amode |
+                         PSW32_MASK_IO | PSW32_MASK_EXT | PSW32_MASK_MCHECK |
+                         PSW32_MASK_PSTATE;
+#endif
+       psw_kernel_bits = PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME |
+                         PSW_MASK_MCHECK | PSW_DEFAULT_KEY;
+
+       if (MACHINE_HAS_MVCOS) {
+               printk("mvcos available.\n");
+               memcpy(&uaccess, &uaccess_mvcos_switch, sizeof(uaccess));
+       } else {
+               printk("mvcos not available.\n");
+               memcpy(&uaccess, &uaccess_pt, sizeof(uaccess));
+       }
+}
+
+/*
+ * Switch kernel/user addressing modes?
+ */
+static int __init early_parse_switch_amode(char *p)
+{
+       switch_amode = 1;
+       return 0;
+}
+early_param("switch_amode", early_parse_switch_amode);
+
+#else /* CONFIG_S390_SWITCH_AMODE */
+static inline void set_amode_and_uaccess(unsigned long user_amode,
+                                        unsigned long user32_amode)
+{
+}
+#endif /* CONFIG_S390_SWITCH_AMODE */
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+unsigned int s390_noexec = 0;
+EXPORT_SYMBOL_GPL(s390_noexec);
+
+/*
+ * Enable execute protection?
+ */
+static int __init early_parse_noexec(char *p)
+{
+       if (!strncmp(p, "off", 3))
+               return 0;
+       switch_amode = 1;
+       s390_noexec = 1;
+       return 0;
+}
+early_param("noexec", early_parse_noexec);
+#endif /* CONFIG_S390_EXEC_PROTECT */
+
+static void setup_addressing_mode(void)
+{
+       if (s390_noexec) {
+               printk("S390 execute protection active, ");
+               set_amode_and_uaccess(PSW_ASC_SECONDARY, PSW32_ASC_SECONDARY);
+               return;
+       }
+       if (switch_amode) {
+               printk("S390 address spaces switched, ");
+               set_amode_and_uaccess(PSW_ASC_PRIMARY, PSW32_ASC_PRIMARY);
+       }
+}
+
 static void __init
 setup_lowcore(void)
 {
@@ -402,19 +486,21 @@ setup_lowcore(void)
        lc->restart_psw.mask = PSW_BASE_BITS | PSW_DEFAULT_KEY;
        lc->restart_psw.addr =
                PSW_ADDR_AMODE | (unsigned long) restart_int_handler;
-       lc->external_new_psw.mask = PSW_KERNEL_BITS;
+       if (switch_amode)
+               lc->restart_psw.mask |= PSW_ASC_HOME;
+       lc->external_new_psw.mask = psw_kernel_bits;
        lc->external_new_psw.addr =
                PSW_ADDR_AMODE | (unsigned long) ext_int_handler;
-       lc->svc_new_psw.mask = PSW_KERNEL_BITS | PSW_MASK_IO | PSW_MASK_EXT;
+       lc->svc_new_psw.mask = psw_kernel_bits | PSW_MASK_IO | PSW_MASK_EXT;
        lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call;
-       lc->program_new_psw.mask = PSW_KERNEL_BITS;
+       lc->program_new_psw.mask = psw_kernel_bits;
        lc->program_new_psw.addr =
                PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
        lc->mcck_new_psw.mask =
-               PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
+               psw_kernel_bits & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
        lc->mcck_new_psw.addr =
                PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
-       lc->io_new_psw.mask = PSW_KERNEL_BITS;
+       lc->io_new_psw.mask = psw_kernel_bits;
        lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
        lc->ipl_device = S390_lowcore.ipl_device;
        lc->jiffy_timer = -1LL;
@@ -439,7 +525,7 @@ setup_lowcore(void)
 static void __init
 setup_resources(void)
 {
-       struct resource *res;
+       struct resource *res, *sub_res;
        int i;
 
        code_resource.start = (unsigned long) &_text;
@@ -464,8 +550,38 @@ setup_resources(void)
                res->start = memory_chunk[i].addr;
                res->end = memory_chunk[i].addr +  memory_chunk[i].size - 1;
                request_resource(&iomem_resource, res);
-               request_resource(res, &code_resource);
-               request_resource(res, &data_resource);
+
+               if (code_resource.start >= res->start  &&
+                       code_resource.start <= res->end &&
+                       code_resource.end > res->end) {
+                       sub_res = alloc_bootmem_low(sizeof(struct resource));
+                       memcpy(sub_res, &code_resource,
+                               sizeof(struct resource));
+                       sub_res->end = res->end;
+                       code_resource.start = res->end + 1;
+                       request_resource(res, sub_res);
+               }
+
+               if (code_resource.start >= res->start &&
+                       code_resource.start <= res->end &&
+                       code_resource.end <= res->end)
+                       request_resource(res, &code_resource);
+
+               if (data_resource.start >= res->start &&
+                       data_resource.start <= res->end &&
+                       data_resource.end > res->end) {
+                       sub_res = alloc_bootmem_low(sizeof(struct resource));
+                       memcpy(sub_res, &data_resource,
+                               sizeof(struct resource));
+                       sub_res->end = res->end;
+                       data_resource.start = res->end + 1;
+                       request_resource(res, sub_res);
+               }
+
+               if (data_resource.start >= res->start &&
+                       data_resource.start <= res->end &&
+                       data_resource.end <= res->end)
+                       request_resource(res, &data_resource);
        }
 }
 
@@ -495,16 +611,13 @@ static void __init setup_memory_end(void)
        }
        if (!memory_end)
                memory_end = memory_size;
-       if (real_size > memory_end)
-               printk("More memory detected than supported. Unused: %luk\n",
-                      (real_size - memory_end) >> 10);
 }
 
 static void __init
 setup_memory(void)
 {
         unsigned long bootmap_size;
-       unsigned long start_pfn, end_pfn, init_pfn;
+       unsigned long start_pfn, end_pfn;
        int i;
 
        /*
@@ -514,10 +627,6 @@ setup_memory(void)
        start_pfn = PFN_UP(__pa(&_end));
        end_pfn = max_pfn = PFN_DOWN(memory_end);
 
-       /* Initialize storage key for kernel pages */
-       for (init_pfn = 0 ; init_pfn < start_pfn; init_pfn++)
-               page_set_storage_key(init_pfn << PAGE_SHIFT, PAGE_DEFAULT_KEY);
-
 #ifdef CONFIG_BLK_DEV_INITRD
        /*
         * Move the initrd in case the bitmap of the bootmem allocater
@@ -651,6 +760,7 @@ setup_arch(char **cmdline_p)
        parse_early_param();
 
        setup_memory_end();
+       setup_addressing_mode();
        setup_memory();
        setup_resources();
        setup_lowcore();
@@ -694,6 +804,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
         struct cpuinfo_S390 *cpuinfo;
        unsigned long n = (unsigned long) v - 1;
 
+       s390_adjust_jiffies();
        preempt_disable();
        if (!n) {
                seq_printf(m, "vendor_id       : IBM/S390\n"
index 4c8a795..554f9cf 100644 (file)
@@ -119,7 +119,7 @@ static int save_sigregs(struct pt_regs *regs, _sigregs __user *sregs)
 
        /* Copy a 'clean' PSW mask to the user to avoid leaking
           information about whether PER is currently on.  */
-       user_sregs.regs.psw.mask = PSW_MASK_MERGE(PSW_USER_BITS, regs->psw.mask);
+       user_sregs.regs.psw.mask = PSW_MASK_MERGE(psw_user_bits, regs->psw.mask);
        user_sregs.regs.psw.addr = regs->psw.addr;
        memcpy(&user_sregs.regs.gprs, &regs->gprs, sizeof(sregs->regs.gprs));
        memcpy(&user_sregs.regs.acrs, current->thread.acrs,
index c0cd255..65b5232 100644 (file)
 
 #include <linux/module.h>
 #include <linux/init.h>
-
 #include <linux/mm.h>
 #include <linux/spinlock.h>
 #include <linux/kernel_stat.h>
 #include <linux/smp_lock.h>
-
 #include <linux/delay.h>
 #include <linux/cache.h>
 #include <linux/interrupt.h>
 #include <linux/cpu.h>
-
+#include <linux/timex.h>
+#include <asm/setup.h>
 #include <asm/sigp.h>
 #include <asm/pgalloc.h>
 #include <asm/irq.h>
 #include <asm/s390_ext.h>
 #include <asm/cpcmd.h>
 #include <asm/tlbflush.h>
+#include <asm/timer.h>
 
 extern volatile int __cpu_logical_map[];
 
@@ -53,12 +53,6 @@ cpumask_t cpu_possible_map = CPU_MASK_NONE;
 
 static struct task_struct *current_set[NR_CPUS];
 
-/*
- * Reboot, halt and power_off routines for SMP.
- */
-extern char vmhalt_cmd[];
-extern char vmpoff_cmd[];
-
 static void smp_ext_bitcall(int, ec_bit_sig);
 static void smp_ext_bitcall_others(ec_bit_sig);
 
@@ -200,7 +194,7 @@ int smp_call_function_on(void (*func) (void *info), void *info,
 }
 EXPORT_SYMBOL(smp_call_function_on);
 
-static inline void do_send_stop(void)
+static void do_send_stop(void)
 {
         int cpu, rc;
 
@@ -214,7 +208,7 @@ static inline void do_send_stop(void)
        }
 }
 
-static inline void do_store_status(void)
+static void do_store_status(void)
 {
         int cpu, rc;
 
@@ -230,7 +224,7 @@ static inline void do_store_status(void)
         }
 }
 
-static inline void do_wait_for_stop(void)
+static void do_wait_for_stop(void)
 {
        int cpu;
 
@@ -250,7 +244,7 @@ static inline void do_wait_for_stop(void)
 void smp_send_stop(void)
 {
        /* Disable all interrupts/machine checks */
-       __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK);
+       __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
 
         /* write magic number to zero page (absolute 0) */
        lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC;
@@ -298,7 +292,7 @@ void machine_power_off_smp(void)
  * cpus are handled.
  */
 
-void do_ext_call_interrupt(__u16 code)
+static void do_ext_call_interrupt(__u16 code)
 {
         unsigned long bits;
 
@@ -385,7 +379,7 @@ struct ec_creg_mask_parms {
 /*
  * callback for setting/clearing control bits
  */
-void smp_ctl_bit_callback(void *info) {
+static void smp_ctl_bit_callback(void *info) {
        struct ec_creg_mask_parms *pp = info;
        unsigned long cregs[16];
        int i;
@@ -458,17 +452,15 @@ __init smp_count_cpus(void)
 /*
  *      Activate a secondary processor.
  */
-extern void init_cpu_timer(void);
-extern void init_cpu_vtimer(void);
-
 int __devinit start_secondary(void *cpuvoid)
 {
         /* Setup the cpu */
         cpu_init();
        preempt_disable();
-        /* init per CPU timer */
+       /* Enable TOD clock interrupts on the secondary cpu. */
         init_cpu_timer();
 #ifdef CONFIG_VIRT_TIMER
+       /* Enable cpu timer interrupts on the secondary cpu. */
         init_cpu_vtimer();
 #endif
        /* Enable pfault pseudo page faults on this cpu. */
@@ -542,7 +534,7 @@ smp_put_cpu(int cpu)
        spin_unlock_irqrestore(&smp_reserve_lock, flags);
 }
 
-static inline int
+static int
 cpu_stopped(int cpu)
 {
        __u32 status;
index 0d14a47..2e5c65a 100644 (file)
 #include <linux/stacktrace.h>
 #include <linux/kallsyms.h>
 
-static inline unsigned long save_context_stack(struct stack_trace *trace,
-                                              unsigned int *skip,
-                                              unsigned long sp,
-                                              unsigned long low,
-                                              unsigned long high)
+static unsigned long save_context_stack(struct stack_trace *trace,
+                                       unsigned int *skip,
+                                       unsigned long sp,
+                                       unsigned long low,
+                                       unsigned long high)
 {
        struct stack_frame *sf;
        struct pt_regs *regs;
index 6cceed4..3b91f27 100644 (file)
 #include <asm/irq.h>
 #include <asm/irq_regs.h>
 #include <asm/timer.h>
+#include <asm/etr.h>
 
 /* change this if you have some constant time drift */
 #define USECS_PER_JIFFY     ((unsigned long) 1000000/HZ)
 #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
 
+/* The value of the TOD clock for 1.1.1970. */
+#define TOD_UNIX_EPOCH 0x7d91048bca000000ULL
+
 /*
  * Create a small time difference between the timer interrupts
  * on the different cpus to avoid lock contention.
@@ -51,6 +55,7 @@
 #define TICK_SIZE tick
 
 static ext_int_info_t ext_int_info_cc;
+static ext_int_info_t ext_int_etr_cc;
 static u64 init_timer_cc;
 static u64 jiffies_timer_cc;
 static u64 xtime_cc;
@@ -89,29 +94,21 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime)
 #define s390_do_profile()      do { ; } while(0)
 #endif /* CONFIG_PROFILING */
 
-
 /*
- * timer_interrupt() needs to keep up the real-time clock,
- * as well as call the "do_timer()" routine every clocktick
+ * Advance the per cpu tick counter up to the time given with the
+ * "time" argument. The per cpu update consists of accounting
+ * the virtual cpu time, calling update_process_times and calling
+ * the profiling hook. If xtime is before time it is advanced as well.
  */
-void account_ticks(void)
+void account_ticks(u64 time)
 {
-       __u64 tmp;
        __u32 ticks;
+       __u64 tmp;
 
        /* Calculate how many ticks have passed. */
-       if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) {
-               /*
-                * We have to program the clock comparator even if
-                * no tick has passed. That happens if e.g. an i/o
-                * interrupt wakes up an idle processor that has
-                * switched off its hz timer.
-                */
-               tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
-               asm volatile ("SCKC %0" : : "m" (tmp));
+       if (time < S390_lowcore.jiffy_timer)
                return;
-       }
-       tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer;
+       tmp = time - S390_lowcore.jiffy_timer;
        if (tmp >= 2*CLK_TICKS_PER_JIFFY) {  /* more than two ticks ? */
                ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1;
                S390_lowcore.jiffy_timer +=
@@ -124,10 +121,6 @@ void account_ticks(void)
                S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
        }
 
-       /* set clock comparator for next tick */
-       tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
-        asm volatile ("SCKC %0" : : "m" (tmp));
-
 #ifdef CONFIG_SMP
        /*
         * Do not rely on the boot cpu to do the calls to do_timer.
@@ -173,7 +166,7 @@ int sysctl_hz_timer = 1;
  * Stop the HZ tick on the current CPU.
  * Only cpu_idle may call this function.
  */
-static inline void stop_hz_timer(void)
+static void stop_hz_timer(void)
 {
        unsigned long flags;
        unsigned long seq, next;
@@ -210,20 +203,21 @@ static inline void stop_hz_timer(void)
                if (timer >= jiffies_timer_cc)
                        todval = timer;
        }
-       asm volatile ("SCKC %0" : : "m" (todval));
+       set_clock_comparator(todval);
 }
 
 /*
  * Start the HZ tick on the current CPU.
  * Only cpu_idle may call this function.
  */
-static inline void start_hz_timer(void)
+static void start_hz_timer(void)
 {
        BUG_ON(!in_interrupt());
 
        if (!cpu_isset(smp_processor_id(), nohz_cpu_mask))
                return;
-       account_ticks();
+       account_ticks(get_clock());
+       set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
        cpu_clear(smp_processor_id(), nohz_cpu_mask);
 }
 
@@ -245,7 +239,7 @@ static struct notifier_block nohz_idle_nb = {
        .notifier_call = nohz_idle_notify,
 };
 
-void __init nohz_init(void)
+static void __init nohz_init(void)
 {
        if (register_idle_notifier(&nohz_idle_nb))
                panic("Couldn't register idle notifier");
@@ -254,24 +248,57 @@ void __init nohz_init(void)
 #endif
 
 /*
- * Start the clock comparator on the current CPU.
+ * Set up per cpu jiffy timer and set the clock comparator.
+ */
+static void setup_jiffy_timer(void)
+{
+       /* Set up clock comparator to next jiffy. */
+       S390_lowcore.jiffy_timer =
+               jiffies_timer_cc + (jiffies_64 + 1) * CLK_TICKS_PER_JIFFY;
+       set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
+}
+
+/*
+ * Set up lowcore and control register of the current cpu to
+ * enable TOD clock and clock comparator interrupts.
  */
 void init_cpu_timer(void)
 {
-       unsigned long cr0;
-       __u64 timer;
+       setup_jiffy_timer();
 
-       timer = jiffies_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY;
-       S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY;
-       timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION;
-       asm volatile ("SCKC %0" : : "m" (timer));
-        /* allow clock comparator timer interrupt */
-       __ctl_store(cr0, 0, 0);
-        cr0 |= 0x800;
-       __ctl_load(cr0, 0, 0);
+       /* Enable clock comparator timer interrupt. */
+       __ctl_set_bit(0,11);
+
+       /* Always allow ETR external interrupts, even without an ETR. */
+       __ctl_set_bit(0, 4);
 }
 
-extern void vtime_init(void);
+static void clock_comparator_interrupt(__u16 code)
+{
+       /* set clock comparator for next tick */
+       set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
+}
+
+static void etr_reset(void);
+static void etr_init(void);
+static void etr_ext_handler(__u16);
+
+/*
+ * Get the TOD clock running.
+ */
+static u64 __init reset_tod_clock(void)
+{
+       u64 time;
+
+       etr_reset();
+       if (store_clock(&time) == 0)
+               return time;
+       /* TOD clock not running. Set the clock to Unix Epoch. */
+       if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0)
+               panic("TOD clock not operational.");
+
+       return TOD_UNIX_EPOCH;
+}
 
 static cycle_t read_tod_clock(void)
 {
@@ -295,48 +322,31 @@ static struct clocksource clocksource_tod = {
  */
 void __init time_init(void)
 {
-       __u64 set_time_cc;
-       int cc;
-
-        /* kick the TOD clock */
-       asm volatile(
-               "       stck    0(%2)\n"
-               "       ipm     %0\n"
-               "       srl     %0,28"
-               : "=d" (cc), "=m" (init_timer_cc)
-               : "a" (&init_timer_cc) : "cc");
-        switch (cc) {
-        case 0: /* clock in set state: all is fine */
-                break;
-        case 1: /* clock in non-set state: FIXME */
-                printk("time_init: TOD clock in non-set state\n");
-                break;
-        case 2: /* clock in error state: FIXME */
-                printk("time_init: TOD clock in error state\n");
-                break;
-        case 3: /* clock in stopped or not-operational state: FIXME */
-                printk("time_init: TOD clock stopped/non-operational\n");
-                break;
-        }
+       init_timer_cc = reset_tod_clock();
+       xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY;
        jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY;
 
        /* set xtime */
-       xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY;
-       set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
-               (0x3c26700LL*1000000*4096);
-        tod_to_timeval(set_time_cc, &xtime);
+       tod_to_timeval(init_timer_cc - TOD_UNIX_EPOCH, &xtime);
         set_normalized_timespec(&wall_to_monotonic,
                                 -xtime.tv_sec, -xtime.tv_nsec);
 
        /* request the clock comparator external interrupt */
-       if (register_early_external_interrupt(0x1004, NULL,
+       if (register_early_external_interrupt(0x1004,
+                                             clock_comparator_interrupt,
                                              &ext_int_info_cc) != 0)
                 panic("Couldn't request external interrupt 0x1004");
 
        if (clocksource_register(&clocksource_tod) != 0)
                panic("Could not register TOD clock source");
 
-        init_cpu_timer();
+       /* request the etr external interrupt */
+       if (register_early_external_interrupt(0x1406, etr_ext_handler,
+                                             &ext_int_etr_cc) != 0)
+               panic("Couldn't request external interrupt 0x1406");
+
+       /* Enable TOD clock interrupts on the boot cpu. */
+       init_cpu_timer();
 
 #ifdef CONFIG_NO_IDLE_HZ
        nohz_init();
@@ -345,5 +355,1048 @@ void __init time_init(void)
 #ifdef CONFIG_VIRT_TIMER
        vtime_init();
 #endif
+       etr_init();
+}
+
+/*
+ * External Time Reference (ETR) code.
+ */
+static int etr_port0_online;
+static int etr_port1_online;
+
+static int __init early_parse_etr(char *p)
+{
+       if (strncmp(p, "off", 3) == 0)
+               etr_port0_online = etr_port1_online = 0;
+       else if (strncmp(p, "port0", 5) == 0)
+               etr_port0_online = 1;
+       else if (strncmp(p, "port1", 5) == 0)
+               etr_port1_online = 1;
+       else if (strncmp(p, "on", 2) == 0)
+               etr_port0_online = etr_port1_online = 1;
+       return 0;
+}
+early_param("etr", early_parse_etr);
+
+enum etr_event {
+       ETR_EVENT_PORT0_CHANGE,
+       ETR_EVENT_PORT1_CHANGE,
+       ETR_EVENT_PORT_ALERT,
+       ETR_EVENT_SYNC_CHECK,
+       ETR_EVENT_SWITCH_LOCAL,
+       ETR_EVENT_UPDATE,
+};
+
+enum etr_flags {
+       ETR_FLAG_ENOSYS,
+       ETR_FLAG_EACCES,
+       ETR_FLAG_STEAI,
+};
+
+/*
+ * Valid bit combinations of the eacr register are (x = don't care):
+ * e0 e1 dp p0 p1 ea es sl
+ *  0  0  x  0 0  0  0  0  initial, disabled state
+ *  0  0  x  0 1  1  0  0  port 1 online
+ *  0  0  x  1 0  1  0  0  port 0 online
+ *  0  0  x  1 1  1  0  0  both ports online
+ *  0  1  x  0 1  1  0  0  port 1 online and usable, ETR or PPS mode
+ *  0  1  x  0 1  1  0  1  port 1 online, usable and ETR mode
+ *  0  1  x  0 1  1  1  0  port 1 online, usable, PPS mode, in-sync
+ *  0  1  x  0 1  1  1  1  port 1 online, usable, ETR mode, in-sync
+ *  0  1  x  1 1  1  0  0  both ports online, port 1 usable
+ *  0  1  x  1 1  1  1  0  both ports online, port 1 usable, PPS mode, in-sync
+ *  0  1  x  1 1  1  1  1  both ports online, port 1 usable, ETR mode, in-sync
+ *  1  0  x  1 0  1  0  0  port 0 online and usable, ETR or PPS mode
+ *  1  0  x  1 0  1  0  1  port 0 online, usable and ETR mode
+ *  1  0  x  1 0  1  1  0  port 0 online, usable, PPS mode, in-sync
+ *  1  0  x  1 0  1  1  1  port 0 online, usable, ETR mode, in-sync
+ *  1  0  x  1 1  1  0  0  both ports online, port 0 usable
+ *  1  0  x  1 1  1  1  0  both ports online, port 0 usable, PPS mode, in-sync
+ *  1  0  x  1 1  1  1  1  both ports online, port 0 usable, ETR mode, in-sync
+ *  1  1  x  1 1  1  1  0  both ports online & usable, ETR, in-sync
+ *  1  1  x  1 1  1  1  1  both ports online & usable, ETR, in-sync
+ */
+static struct etr_eacr etr_eacr;
+static u64 etr_tolec;                  /* time of last eacr update */
+static unsigned long etr_flags;
+static struct etr_aib etr_port0;
+static int etr_port0_uptodate;
+static struct etr_aib etr_port1;
+static int etr_port1_uptodate;
+static unsigned long etr_events;
+static struct timer_list etr_timer;
+static struct tasklet_struct etr_tasklet;
+static DEFINE_PER_CPU(atomic_t, etr_sync_word);
+
+static void etr_timeout(unsigned long dummy);
+static void etr_tasklet_fn(unsigned long dummy);
+
+/*
+ * The etr get_clock function. It will write the current clock value
+ * to the clock pointer and return 0 if the clock is in sync with the
+ * external time source. If the clock mode is local it will return
+ * -ENOSYS and -EAGAIN if the clock is not in sync with the external
+ * reference. This function is what ETR is all about..
+ */
+int get_sync_clock(unsigned long long *clock)
+{
+       atomic_t *sw_ptr;
+       unsigned int sw0, sw1;
+
+       sw_ptr = &get_cpu_var(etr_sync_word);
+       sw0 = atomic_read(sw_ptr);
+       *clock = get_clock();
+       sw1 = atomic_read(sw_ptr);
+       put_cpu_var(etr_sync_sync);
+       if (sw0 == sw1 && (sw0 & 0x80000000U))
+               /* Success: time is in sync. */
+               return 0;
+       if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+               return -ENOSYS;
+       if (test_bit(ETR_FLAG_EACCES, &etr_flags))
+               return -EACCES;
+       return -EAGAIN;
+}
+EXPORT_SYMBOL(get_sync_clock);
+
+/*
+ * Make get_sync_clock return -EAGAIN.
+ */
+static void etr_disable_sync_clock(void *dummy)
+{
+       atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word);
+       /*
+        * Clear the in-sync bit 2^31. All get_sync_clock calls will
+        * fail until the sync bit is turned back on. In addition
+        * increase the "sequence" counter to avoid the race of an
+        * etr event and the complete recovery against get_sync_clock.
+        */
+       atomic_clear_mask(0x80000000, sw_ptr);
+       atomic_inc(sw_ptr);
+}
+
+/*
+ * Make get_sync_clock return 0 again.
+ * Needs to be called from a context disabled for preemption.
+ */
+static void etr_enable_sync_clock(void)
+{
+       atomic_t *sw_ptr = &__get_cpu_var(etr_sync_word);
+       atomic_set_mask(0x80000000, sw_ptr);
+}
+
+/*
+ * Reset ETR attachment.
+ */
+static void etr_reset(void)
+{
+       etr_eacr =  (struct etr_eacr) {
+               .e0 = 0, .e1 = 0, ._pad0 = 4, .dp = 0,
+               .p0 = 0, .p1 = 0, ._pad1 = 0, .ea = 0,
+               .es = 0, .sl = 0 };
+       if (etr_setr(&etr_eacr) == 0)
+               etr_tolec = get_clock();
+       else {
+               set_bit(ETR_FLAG_ENOSYS, &etr_flags);
+               if (etr_port0_online || etr_port1_online) {
+                       printk(KERN_WARNING "Running on non ETR capable "
+                              "machine, only local mode available.\n");
+                       etr_port0_online = etr_port1_online = 0;
+               }
+       }
+}
+
+static void etr_init(void)
+{
+       struct etr_aib aib;
+
+       if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+               return;
+       /* Check if this machine has the steai instruction. */
+       if (etr_steai(&aib, ETR_STEAI_STEPPING_PORT) == 0)
+               set_bit(ETR_FLAG_STEAI, &etr_flags);
+       setup_timer(&etr_timer, etr_timeout, 0UL);
+       tasklet_init(&etr_tasklet, etr_tasklet_fn, 0);
+       if (!etr_port0_online && !etr_port1_online)
+               set_bit(ETR_FLAG_EACCES, &etr_flags);
+       if (etr_port0_online) {
+               set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+               tasklet_hi_schedule(&etr_tasklet);
+       }
+       if (etr_port1_online) {
+               set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+               tasklet_hi_schedule(&etr_tasklet);
+       }
+}
+
+/*
+ * Two sorts of ETR machine checks. The architecture reads:
+ * "When a machine-check niterruption occurs and if a switch-to-local or
+ *  ETR-sync-check interrupt request is pending but disabled, this pending
+ *  disabled interruption request is indicated and is cleared".
+ * Which means that we can get etr_switch_to_local events from the machine
+ * check handler although the interruption condition is disabled. Lovely..
+ */
+
+/*
+ * Switch to local machine check. This is called when the last usable
+ * ETR port goes inactive. After switch to local the clock is not in sync.
+ */
+void etr_switch_to_local(void)
+{
+       if (!etr_eacr.sl)
+               return;
+       etr_disable_sync_clock(NULL);
+       set_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events);
+       tasklet_hi_schedule(&etr_tasklet);
+}
+
+/*
+ * ETR sync check machine check. This is called when the ETR OTE and the
+ * local clock OTE are farther apart than the ETR sync check tolerance.
+ * After a ETR sync check the clock is not in sync. The machine check
+ * is broadcasted to all cpus at the same time.
+ */
+void etr_sync_check(void)
+{
+       if (!etr_eacr.es)
+               return;
+       etr_disable_sync_clock(NULL);
+       set_bit(ETR_EVENT_SYNC_CHECK, &etr_events);
+       tasklet_hi_schedule(&etr_tasklet);
+}
+
+/*
+ * ETR external interrupt. There are two causes:
+ * 1) port state change, check the usability of the port
+ * 2) port alert, one of the ETR-data-validity bits (v1-v2 bits of the
+ *    sldr-status word) or ETR-data word 1 (edf1) or ETR-data word 3 (edf3)
+ *    or ETR-data word 4 (edf4) has changed.
+ */
+static void etr_ext_handler(__u16 code)
+{
+       struct etr_interruption_parameter *intparm =
+               (struct etr_interruption_parameter *) &S390_lowcore.ext_params;
+
+       if (intparm->pc0)
+               /* ETR port 0 state change. */
+               set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+       if (intparm->pc1)
+               /* ETR port 1 state change. */
+               set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+       if (intparm->eai)
+               /*
+                * ETR port alert on either port 0, 1 or both.
+                * Both ports are not up-to-date now.
+                */
+               set_bit(ETR_EVENT_PORT_ALERT, &etr_events);
+       tasklet_hi_schedule(&etr_tasklet);
+}
+
+static void etr_timeout(unsigned long dummy)
+{
+       set_bit(ETR_EVENT_UPDATE, &etr_events);
+       tasklet_hi_schedule(&etr_tasklet);
+}
+
+/*
+ * Check if the etr mode is pss.
+ */
+static inline int etr_mode_is_pps(struct etr_eacr eacr)
+{
+       return eacr.es && !eacr.sl;
+}
+
+/*
+ * Check if the etr mode is etr.
+ */
+static inline int etr_mode_is_etr(struct etr_eacr eacr)
+{
+       return eacr.es && eacr.sl;
+}
+
+/*
+ * Check if the port can be used for TOD synchronization.
+ * For PPS mode the port has to receive OTEs. For ETR mode
+ * the port has to receive OTEs, the ETR stepping bit has to
+ * be zero and the validity bits for data frame 1, 2, and 3
+ * have to be 1.
+ */
+static int etr_port_valid(struct etr_aib *aib, int port)
+{
+       unsigned int psc;
+
+       /* Check that this port is receiving OTEs. */
+       if (aib->tsp == 0)
+               return 0;
+
+       psc = port ? aib->esw.psc1 : aib->esw.psc0;
+       if (psc == etr_lpsc_pps_mode)
+               return 1;
+       if (psc == etr_lpsc_operational_step)
+               return !aib->esw.y && aib->slsw.v1 &&
+                       aib->slsw.v2 && aib->slsw.v3;
+       return 0;
+}
+
+/*
+ * Check if two ports are on the same network.
+ */
+static int etr_compare_network(struct etr_aib *aib1, struct etr_aib *aib2)
+{
+       // FIXME: any other fields we have to compare?
+       return aib1->edf1.net_id == aib2->edf1.net_id;
+}
+
+/*
+ * Wrapper for etr_stei that converts physical port states
+ * to logical port states to be consistent with the output
+ * of stetr (see etr_psc vs. etr_lpsc).
+ */
+static void etr_steai_cv(struct etr_aib *aib, unsigned int func)
+{
+       BUG_ON(etr_steai(aib, func) != 0);
+       /* Convert port state to logical port state. */
+       if (aib->esw.psc0 == 1)
+               aib->esw.psc0 = 2;
+       else if (aib->esw.psc0 == 0 && aib->esw.p == 0)
+               aib->esw.psc0 = 1;
+       if (aib->esw.psc1 == 1)
+               aib->esw.psc1 = 2;
+       else if (aib->esw.psc1 == 0 && aib->esw.p == 1)
+               aib->esw.psc1 = 1;
+}
+
+/*
+ * Check if the aib a2 is still connected to the same attachment as
+ * aib a1, the etv values differ by one and a2 is valid.
+ */
+static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p)
+{
+       int state_a1, state_a2;
+
+       /* Paranoia check: e0/e1 should better be the same. */
+       if (a1->esw.eacr.e0 != a2->esw.eacr.e0 ||
+           a1->esw.eacr.e1 != a2->esw.eacr.e1)
+               return 0;
+
+       /* Still connected to the same etr ? */
+       state_a1 = p ? a1->esw.psc1 : a1->esw.psc0;
+       state_a2 = p ? a2->esw.psc1 : a2->esw.psc0;
+       if (state_a1 == etr_lpsc_operational_step) {
+               if (state_a2 != etr_lpsc_operational_step ||
+                   a1->edf1.net_id != a2->edf1.net_id ||
+                   a1->edf1.etr_id != a2->edf1.etr_id ||
+                   a1->edf1.etr_pn != a2->edf1.etr_pn)
+                       return 0;
+       } else if (state_a2 != etr_lpsc_pps_mode)
+               return 0;
+
+       /* The ETV value of a2 needs to be ETV of a1 + 1. */
+       if (a1->edf2.etv + 1 != a2->edf2.etv)
+               return 0;
+
+       if (!etr_port_valid(a2, p))
+               return 0;
+
+       return 1;
+}
+
+/*
+ * The time is "clock". xtime is what we think the time is.
+ * Adjust the value by a multiple of jiffies and add the delta to ntp.
+ * "delay" is an approximation how long the synchronization took. If
+ * the time correction is positive, then "delay" is subtracted from
+ * the time difference and only the remaining part is passed to ntp.
+ */
+static void etr_adjust_time(unsigned long long clock, unsigned long long delay)
+{
+       unsigned long long delta, ticks;
+       struct timex adjust;
+
+       /*
+        * We don't have to take the xtime lock because the cpu
+        * executing etr_adjust_time is running disabled in
+        * tasklet context and all other cpus are looping in
+        * etr_sync_cpu_start.
+        */
+       if (clock > xtime_cc) {
+               /* It is later than we thought. */
+               delta = ticks = clock - xtime_cc;
+               delta = ticks = (delta < delay) ? 0 : delta - delay;
+               delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
+               init_timer_cc = init_timer_cc + delta;
+               jiffies_timer_cc = jiffies_timer_cc + delta;
+               xtime_cc = xtime_cc + delta;
+               adjust.offset = ticks * (1000000 / HZ);
+       } else {
+               /* It is earlier than we thought. */
+               delta = ticks = xtime_cc - clock;
+               delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
+               init_timer_cc = init_timer_cc - delta;
+               jiffies_timer_cc = jiffies_timer_cc - delta;
+               xtime_cc = xtime_cc - delta;
+               adjust.offset = -ticks * (1000000 / HZ);
+       }
+       if (adjust.offset != 0) {
+               printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n",
+                      adjust.offset);
+               adjust.modes = ADJ_OFFSET_SINGLESHOT;
+               do_adjtimex(&adjust);
+       }
+}
+
+static void etr_sync_cpu_start(void *dummy)
+{
+       int *in_sync = dummy;
+
+       etr_enable_sync_clock();
+       /*
+        * This looks like a busy wait loop but it isn't. etr_sync_cpus
+        * is called on all other cpus while the TOD clocks is stopped.
+        * __udelay will stop the cpu on an enabled wait psw until the
+        * TOD is running again.
+        */
+       while (*in_sync == 0)
+               __udelay(1);
+       if (*in_sync != 1)
+               /* Didn't work. Clear per-cpu in sync bit again. */
+               etr_disable_sync_clock(NULL);
+       /*
+        * This round of TOD syncing is done. Set the clock comparator
+        * to the next tick and let the processor continue.
+        */
+       setup_jiffy_timer();
+}
+
+static void etr_sync_cpu_end(void *dummy)
+{
+}
+
+/*
+ * Sync the TOD clock using the port refered to by aibp. This port
+ * has to be enabled and the other port has to be disabled. The
+ * last eacr update has to be more than 1.6 seconds in the past.
+ */
+static int etr_sync_clock(struct etr_aib *aib, int port)
+{
+       struct etr_aib *sync_port;
+       unsigned long long clock, delay;
+       int in_sync, follows;
+       int rc;
+
+       /* Check if the current aib is adjacent to the sync port aib. */
+       sync_port = (port == 0) ? &etr_port0 : &etr_port1;
+       follows = etr_aib_follows(sync_port, aib, port);
+       memcpy(sync_port, aib, sizeof(*aib));
+       if (!follows)
+               return -EAGAIN;
+
+       /*
+        * Catch all other cpus and make them wait until we have
+        * successfully synced the clock. smp_call_function will
+        * return after all other cpus are in etr_sync_cpu_start.
+        */
+       in_sync = 0;
+       preempt_disable();
+       smp_call_function(etr_sync_cpu_start,&in_sync,0,0);
+       local_irq_disable();
+       etr_enable_sync_clock();
+
+       /* Set clock to next OTE. */
+       __ctl_set_bit(14, 21);
+       __ctl_set_bit(0, 29);
+       clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32;
+       if (set_clock(clock) == 0) {
+               __udelay(1);    /* Wait for the clock to start. */
+               __ctl_clear_bit(0, 29);
+               __ctl_clear_bit(14, 21);
+               etr_stetr(aib);
+               /* Adjust Linux timing variables. */
+               delay = (unsigned long long)
+                       (aib->edf2.etv - sync_port->edf2.etv) << 32;
+               etr_adjust_time(clock, delay);
+               setup_jiffy_timer();
+               /* Verify that the clock is properly set. */
+               if (!etr_aib_follows(sync_port, aib, port)) {
+                       /* Didn't work. */
+                       etr_disable_sync_clock(NULL);
+                       in_sync = -EAGAIN;
+                       rc = -EAGAIN;
+               } else {
+                       in_sync = 1;
+                       rc = 0;
+               }
+       } else {
+               /* Could not set the clock ?!? */
+               __ctl_clear_bit(0, 29);
+               __ctl_clear_bit(14, 21);
+               etr_disable_sync_clock(NULL);
+               in_sync = -EAGAIN;
+               rc = -EAGAIN;
+       }
+       local_irq_enable();
+       smp_call_function(etr_sync_cpu_end,NULL,0,0);
+       preempt_enable();
+       return rc;
+}
+
+/*
+ * Handle the immediate effects of the different events.
+ * The port change event is used for online/offline changes.
+ */
+static struct etr_eacr etr_handle_events(struct etr_eacr eacr)
+{
+       if (test_and_clear_bit(ETR_EVENT_SYNC_CHECK, &etr_events))
+               eacr.es = 0;
+       if (test_and_clear_bit(ETR_EVENT_SWITCH_LOCAL, &etr_events))
+               eacr.es = eacr.sl = 0;
+       if (test_and_clear_bit(ETR_EVENT_PORT_ALERT, &etr_events))
+               etr_port0_uptodate = etr_port1_uptodate = 0;
+
+       if (test_and_clear_bit(ETR_EVENT_PORT0_CHANGE, &etr_events)) {
+               if (eacr.e0)
+                       /*
+                        * Port change of an enabled port. We have to
+                        * assume that this can have caused an stepping
+                        * port switch.
+                        */
+                       etr_tolec = get_clock();
+               eacr.p0 = etr_port0_online;
+               if (!eacr.p0)
+                       eacr.e0 = 0;
+               etr_port0_uptodate = 0;
+       }
+       if (test_and_clear_bit(ETR_EVENT_PORT1_CHANGE, &etr_events)) {
+               if (eacr.e1)
+                       /*
+                        * Port change of an enabled port. We have to
+                        * assume that this can have caused an stepping
+                        * port switch.
+                        */
+                       etr_tolec = get_clock();
+               eacr.p1 = etr_port1_online;
+               if (!eacr.p1)
+                       eacr.e1 = 0;
+               etr_port1_uptodate = 0;
+       }
+       clear_bit(ETR_EVENT_UPDATE, &etr_events);
+       return eacr;
+}
+
+/*
+ * Set up a timer that expires after the etr_tolec + 1.6 seconds if
+ * one of the ports needs an update.
+ */
+static void etr_set_tolec_timeout(unsigned long long now)
+{
+       unsigned long micros;
+
+       if ((!etr_eacr.p0 || etr_port0_uptodate) &&
+           (!etr_eacr.p1 || etr_port1_uptodate))
+               return;
+       micros = (now > etr_tolec) ? ((now - etr_tolec) >> 12) : 0;
+       micros = (micros > 1600000) ? 0 : 1600000 - micros;
+       mod_timer(&etr_timer, jiffies + (micros * HZ) / 1000000 + 1);
+}
+
+/*
+ * Set up a time that expires after 1/2 second.
+ */
+static void etr_set_sync_timeout(void)
+{
+       mod_timer(&etr_timer, jiffies + HZ/2);
+}
+
+/*
+ * Update the aib information for one or both ports.
+ */
+static struct etr_eacr etr_handle_update(struct etr_aib *aib,
+                                        struct etr_eacr eacr)
+{
+       /* With both ports disabled the aib information is useless. */
+       if (!eacr.e0 && !eacr.e1)
+               return eacr;
+
+       /* Update port0 or port1 with aib stored in etr_tasklet_fn. */
+       if (aib->esw.q == 0) {
+               /* Information for port 0 stored. */
+               if (eacr.p0 && !etr_port0_uptodate) {
+                       etr_port0 = *aib;
+                       if (etr_port0_online)
+                               etr_port0_uptodate = 1;
+               }
+       } else {
+               /* Information for port 1 stored. */
+               if (eacr.p1 && !etr_port1_uptodate) {
+                       etr_port1 = *aib;
+                       if (etr_port0_online)
+                               etr_port1_uptodate = 1;
+               }
+       }
+
+       /*
+        * Do not try to get the alternate port aib if the clock
+        * is not in sync yet.
+        */
+       if (!eacr.es)
+               return eacr;
+
+       /*
+        * If steai is available we can get the information about
+        * the other port immediately. If only stetr is available the
+        * data-port bit toggle has to be used.
+        */
+       if (test_bit(ETR_FLAG_STEAI, &etr_flags)) {
+               if (eacr.p0 && !etr_port0_uptodate) {
+                       etr_steai_cv(&etr_port0, ETR_STEAI_PORT_0);
+                       etr_port0_uptodate = 1;
+               }
+               if (eacr.p1 && !etr_port1_uptodate) {
+                       etr_steai_cv(&etr_port1, ETR_STEAI_PORT_1);
+                       etr_port1_uptodate = 1;
+               }
+       } else {
+               /*
+                * One port was updated above, if the other
+                * port is not uptodate toggle dp bit.
+                */
+               if ((eacr.p0 && !etr_port0_uptodate) ||
+                   (eacr.p1 && !etr_port1_uptodate))
+                       eacr.dp ^= 1;
+               else
+                       eacr.dp = 0;
+       }
+       return eacr;
+}
+
+/*
+ * Write new etr control register if it differs from the current one.
+ * Return 1 if etr_tolec has been updated as well.
+ */
+static void etr_update_eacr(struct etr_eacr eacr)
+{
+       int dp_changed;
+
+       if (memcmp(&etr_eacr, &eacr, sizeof(eacr)) == 0)
+               /* No change, return. */
+               return;
+       /*
+        * The disable of an active port of the change of the data port
+        * bit can/will cause a change in the data port.
+        */
+       dp_changed = etr_eacr.e0 > eacr.e0 || etr_eacr.e1 > eacr.e1 ||
+               (etr_eacr.dp ^ eacr.dp) != 0;
+       etr_eacr = eacr;
+       etr_setr(&etr_eacr);
+       if (dp_changed)
+               etr_tolec = get_clock();
+}
+
+/*
+ * ETR tasklet. In this function you'll find the main logic. In
+ * particular this is the only function that calls etr_update_eacr(),
+ * it "controls" the etr control register.
+ */
+static void etr_tasklet_fn(unsigned long dummy)
+{
+       unsigned long long now;
+       struct etr_eacr eacr;
+       struct etr_aib aib;
+       int sync_port;
+
+       /* Create working copy of etr_eacr. */
+       eacr = etr_eacr;
+
+       /* Check for the different events and their immediate effects. */
+       eacr = etr_handle_events(eacr);
+
+       /* Check if ETR is supposed to be active. */
+       eacr.ea = eacr.p0 || eacr.p1;
+       if (!eacr.ea) {
+               /* Both ports offline. Reset everything. */
+               eacr.dp = eacr.es = eacr.sl = 0;
+               on_each_cpu(etr_disable_sync_clock, NULL, 0, 1);
+               del_timer_sync(&etr_timer);
+               etr_update_eacr(eacr);
+               set_bit(ETR_FLAG_EACCES, &etr_flags);
+               return;
+       }
+
+       /* Store aib to get the current ETR status word. */
+       BUG_ON(etr_stetr(&aib) != 0);
+       etr_port0.esw = etr_port1.esw = aib.esw;        /* Copy status word. */
+       now = get_clock();
+
+       /*
+        * Update the port information if the last stepping port change
+        * or data port change is older than 1.6 seconds.
+        */
+       if (now >= etr_tolec + (1600000 << 12))
+               eacr = etr_handle_update(&aib, eacr);
+
+       /*
+        * Select ports to enable. The prefered synchronization mode is PPS.
+        * If a port can be enabled depends on a number of things:
+        * 1) The port needs to be online and uptodate. A port is not
+        *    disabled just because it is not uptodate, but it is only
+        *    enabled if it is uptodate.
+        * 2) The port needs to have the same mode (pps / etr).
+        * 3) The port needs to be usable -> etr_port_valid() == 1
+        * 4) To enable the second port the clock needs to be in sync.
+        * 5) If both ports are useable and are ETR ports, the network id
+        *    has to be the same.
+        * The eacr.sl bit is used to indicate etr mode vs. pps mode.
+        */
+       if (eacr.p0 && aib.esw.psc0 == etr_lpsc_pps_mode) {
+               eacr.sl = 0;
+               eacr.e0 = 1;
+               if (!etr_mode_is_pps(etr_eacr))
+                       eacr.es = 0;
+               if (!eacr.es || !eacr.p1 || aib.esw.psc1 != etr_lpsc_pps_mode)
+                       eacr.e1 = 0;
+               // FIXME: uptodate checks ?
+               else if (etr_port0_uptodate && etr_port1_uptodate)
+                       eacr.e1 = 1;
+               sync_port = (etr_port0_uptodate &&
+                            etr_port_valid(&etr_port0, 0)) ? 0 : -1;
+               clear_bit(ETR_FLAG_EACCES, &etr_flags);
+       } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_pps_mode) {
+               eacr.sl = 0;
+               eacr.e0 = 0;
+               eacr.e1 = 1;
+               if (!etr_mode_is_pps(etr_eacr))
+                       eacr.es = 0;
+               sync_port = (etr_port1_uptodate &&
+                            etr_port_valid(&etr_port1, 1)) ? 1 : -1;
+               clear_bit(ETR_FLAG_EACCES, &etr_flags);
+       } else if (eacr.p0 && aib.esw.psc0 == etr_lpsc_operational_step) {
+               eacr.sl = 1;
+               eacr.e0 = 1;
+               if (!etr_mode_is_etr(etr_eacr))
+                       eacr.es = 0;
+               if (!eacr.es || !eacr.p1 ||
+                   aib.esw.psc1 != etr_lpsc_operational_alt)
+                       eacr.e1 = 0;
+               else if (etr_port0_uptodate && etr_port1_uptodate &&
+                        etr_compare_network(&etr_port0, &etr_port1))
+                       eacr.e1 = 1;
+               sync_port = (etr_port0_uptodate &&
+                            etr_port_valid(&etr_port0, 0)) ? 0 : -1;
+               clear_bit(ETR_FLAG_EACCES, &etr_flags);
+       } else if (eacr.p1 && aib.esw.psc1 == etr_lpsc_operational_step) {
+               eacr.sl = 1;
+               eacr.e0 = 0;
+               eacr.e1 = 1;
+               if (!etr_mode_is_etr(etr_eacr))
+                       eacr.es = 0;
+               sync_port = (etr_port1_uptodate &&
+                            etr_port_valid(&etr_port1, 1)) ? 1 : -1;
+               clear_bit(ETR_FLAG_EACCES, &etr_flags);
+       } else {
+               /* Both ports not usable. */
+               eacr.es = eacr.sl = 0;
+               sync_port = -1;
+               set_bit(ETR_FLAG_EACCES, &etr_flags);
+       }
+
+       /*
+        * If the clock is in sync just update the eacr and return.
+        * If there is no valid sync port wait for a port update.
+        */
+       if (eacr.es || sync_port < 0) {
+               etr_update_eacr(eacr);
+               etr_set_tolec_timeout(now);
+               return;
+       }
+
+       /*
+        * Prepare control register for clock syncing
+        * (reset data port bit, set sync check control.
+        */
+       eacr.dp = 0;
+       eacr.es = 1;
+
+       /*
+        * Update eacr and try to synchronize the clock. If the update
+        * of eacr caused a stepping port switch (or if we have to
+        * assume that a stepping port switch has occured) or the
+        * clock syncing failed, reset the sync check control bit
+        * and set up a timer to try again after 0.5 seconds
+        */
+       etr_update_eacr(eacr);
+       if (now < etr_tolec + (1600000 << 12) ||
+           etr_sync_clock(&aib, sync_port) != 0) {
+               /* Sync failed. Try again in 1/2 second. */
+               eacr.es = 0;
+               etr_update_eacr(eacr);
+               etr_set_sync_timeout();
+       } else
+               etr_set_tolec_timeout(now);
+}
+
+/*
+ * Sysfs interface functions
+ */
+static struct sysdev_class etr_sysclass = {
+       set_kset_name("etr")
+};
+
+static struct sys_device etr_port0_dev = {
+       .id     = 0,
+       .cls    = &etr_sysclass,
+};
+
+static struct sys_device etr_port1_dev = {
+       .id     = 1,
+       .cls    = &etr_sysclass,
+};
+
+/*
+ * ETR class attributes
+ */
+static ssize_t etr_stepping_port_show(struct sysdev_class *class, char *buf)
+{
+       return sprintf(buf, "%i\n", etr_port0.esw.p);
+}
+
+static SYSDEV_CLASS_ATTR(stepping_port, 0400, etr_stepping_port_show, NULL);
+
+static ssize_t etr_stepping_mode_show(struct sysdev_class *class, char *buf)
+{
+       char *mode_str;
+
+       if (etr_mode_is_pps(etr_eacr))
+               mode_str = "pps";
+       else if (etr_mode_is_etr(etr_eacr))
+               mode_str = "etr";
+       else
+               mode_str = "local";
+       return sprintf(buf, "%s\n", mode_str);
+}
+
+static SYSDEV_CLASS_ATTR(stepping_mode, 0400, etr_stepping_mode_show, NULL);
+
+/*
+ * ETR port attributes
+ */
+static inline struct etr_aib *etr_aib_from_dev(struct sys_device *dev)
+{
+       if (dev == &etr_port0_dev)
+               return etr_port0_online ? &etr_port0 : NULL;
+       else
+               return etr_port1_online ? &etr_port1 : NULL;
+}
+
+static ssize_t etr_online_show(struct sys_device *dev, char *buf)
+{
+       unsigned int online;
+
+       online = (dev == &etr_port0_dev) ? etr_port0_online : etr_port1_online;
+       return sprintf(buf, "%i\n", online);
+}
+
+static ssize_t etr_online_store(struct sys_device *dev,
+                             const char *buf, size_t count)
+{
+       unsigned int value;
+
+       value = simple_strtoul(buf, NULL, 0);
+       if (value != 0 && value != 1)
+               return -EINVAL;
+       if (test_bit(ETR_FLAG_ENOSYS, &etr_flags))
+               return -ENOSYS;
+       if (dev == &etr_port0_dev) {
+               if (etr_port0_online == value)
+                       return count;   /* Nothing to do. */
+               etr_port0_online = value;
+               set_bit(ETR_EVENT_PORT0_CHANGE, &etr_events);
+               tasklet_hi_schedule(&etr_tasklet);
+       } else {
+               if (etr_port1_online == value)
+                       return count;   /* Nothing to do. */
+               etr_port1_online = value;
+               set_bit(ETR_EVENT_PORT1_CHANGE, &etr_events);
+               tasklet_hi_schedule(&etr_tasklet);
+       }
+       return count;
+}
+
+static SYSDEV_ATTR(online, 0600, etr_online_show, etr_online_store);
+
+static ssize_t etr_stepping_control_show(struct sys_device *dev, char *buf)
+{
+       return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ?
+                      etr_eacr.e0 : etr_eacr.e1);
+}
+
+static SYSDEV_ATTR(stepping_control, 0400, etr_stepping_control_show, NULL);
+
+static ssize_t etr_mode_code_show(struct sys_device *dev, char *buf)
+{
+       if (!etr_port0_online && !etr_port1_online)
+               /* Status word is not uptodate if both ports are offline. */
+               return -ENODATA;
+       return sprintf(buf, "%i\n", (dev == &etr_port0_dev) ?
+                      etr_port0.esw.psc0 : etr_port0.esw.psc1);
+}
+
+static SYSDEV_ATTR(state_code, 0400, etr_mode_code_show, NULL);
+
+static ssize_t etr_untuned_show(struct sys_device *dev, char *buf)
+{
+       struct etr_aib *aib = etr_aib_from_dev(dev);
+
+       if (!aib || !aib->slsw.v1)
+               return -ENODATA;
+       return sprintf(buf, "%i\n", aib->edf1.u);
+}
+
+static SYSDEV_ATTR(untuned, 0400, etr_untuned_show, NULL);
+
+static ssize_t etr_network_id_show(struct sys_device *dev, char *buf)
+{
+       struct etr_aib *aib = etr_aib_from_dev(dev);
+
+       if (!aib || !aib->slsw.v1)
+               return -ENODATA;
+       return sprintf(buf, "%i\n", aib->edf1.net_id);
+}
+
+static SYSDEV_ATTR(network, 0400, etr_network_id_show, NULL);
+
+static ssize_t etr_id_show(struct sys_device *dev, char *buf)
+{
+       struct etr_aib *aib = etr_aib_from_dev(dev);
+
+       if (!aib || !aib->slsw.v1)
+               return -ENODATA;
+       return sprintf(buf, "%i\n", aib->edf1.etr_id);
+}
+
+static SYSDEV_ATTR(id, 0400, etr_id_show, NULL);
+
+static ssize_t etr_port_number_show(struct sys_device *dev, char *buf)
+{
+       struct etr_aib *aib = etr_aib_from_dev(dev);
+
+       if (!aib || !aib->slsw.v1)
+               return -ENODATA;
+       return sprintf(buf, "%i\n", aib->edf1.etr_pn);
+}
+
+static SYSDEV_ATTR(port, 0400, etr_port_number_show, NULL);
+
+static ssize_t etr_coupled_show(struct sys_device *dev, char *buf)
+{
+       struct etr_aib *aib = etr_aib_from_dev(dev);
+
+       if (!aib || !aib->slsw.v3)
+               return -ENODATA;
+       return sprintf(buf, "%i\n", aib->edf3.c);
+}
+
+static SYSDEV_ATTR(coupled, 0400, etr_coupled_show, NULL);
+
+static ssize_t etr_local_time_show(struct sys_device *dev, char *buf)
+{
+       struct etr_aib *aib = etr_aib_from_dev(dev);
+
+       if (!aib || !aib->slsw.v3)
+               return -ENODATA;
+       return sprintf(buf, "%i\n", aib->edf3.blto);
+}
+
+static SYSDEV_ATTR(local_time, 0400, etr_local_time_show, NULL);
+
+static ssize_t etr_utc_offset_show(struct sys_device *dev, char *buf)
+{
+       struct etr_aib *aib = etr_aib_from_dev(dev);
+
+       if (!aib || !aib->slsw.v3)
+               return -ENODATA;
+       return sprintf(buf, "%i\n", aib->edf3.buo);
+}
+
+static SYSDEV_ATTR(utc_offset, 0400, etr_utc_offset_show, NULL);
+
+static struct sysdev_attribute *etr_port_attributes[] = {
+       &attr_online,
+       &attr_stepping_control,
+       &attr_state_code,
+       &attr_untuned,
+       &attr_network,
+       &attr_id,
+       &attr_port,
+       &attr_coupled,
+       &attr_local_time,
+       &attr_utc_offset,
+       NULL
+};
+
+static int __init etr_register_port(struct sys_device *dev)
+{
+       struct sysdev_attribute **attr;
+       int rc;
+
+       rc = sysdev_register(dev);
+       if (rc)
+               goto out;
+       for (attr = etr_port_attributes; *attr; attr++) {
+               rc = sysdev_create_file(dev, *attr);
+               if (rc)
+                       goto out_unreg;
+       }
+       return 0;
+out_unreg:
+       for (; attr >= etr_port_attributes; attr--)
+               sysdev_remove_file(dev, *attr);
+       sysdev_unregister(dev);
+out:
+       return rc;
+}
+
+static void __init etr_unregister_port(struct sys_device *dev)
+{
+       struct sysdev_attribute **attr;
+
+       for (attr = etr_port_attributes; *attr; attr++)
+               sysdev_remove_file(dev, *attr);
+       sysdev_unregister(dev);
+}
+
+static int __init etr_init_sysfs(void)
+{
+       int rc;
+
+       rc = sysdev_class_register(&etr_sysclass);
+       if (rc)
+               goto out;
+       rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_port);
+       if (rc)
+               goto out_unreg_class;
+       rc = sysdev_class_create_file(&etr_sysclass, &attr_stepping_mode);
+       if (rc)
+               goto out_remove_stepping_port;
+       rc = etr_register_port(&etr_port0_dev);
+       if (rc)
+               goto out_remove_stepping_mode;
+       rc = etr_register_port(&etr_port1_dev);
+       if (rc)
+               goto out_remove_port0;
+       return 0;
+
+out_remove_port0:
+       etr_unregister_port(&etr_port0_dev);
+out_remove_stepping_mode:
+       sysdev_class_remove_file(&etr_sysclass, &attr_stepping_mode);
+out_remove_stepping_port:
+       sysdev_class_remove_file(&etr_sysclass, &attr_stepping_port);
+out_unreg_class:
+       sysdev_class_unregister(&etr_sysclass);
+out:
+       return rc;
 }
 
+device_initcall(etr_init_sysfs);
index 3cbb0dc..f0e5a32 100644 (file)
@@ -283,7 +283,7 @@ char *task_show_regs(struct task_struct *task, char *buffer)
        return buffer;
 }
 
-DEFINE_SPINLOCK(die_lock);
+static DEFINE_SPINLOCK(die_lock);
 
 void die(const char * str, struct pt_regs * regs, long err)
 {
@@ -364,8 +364,7 @@ void __kprobes do_single_step(struct pt_regs *regs)
                force_sig(SIGTRAP, current);
 }
 
-asmlinkage void
-default_trap_handler(struct pt_regs * regs, long interruption_code)
+static void default_trap_handler(struct pt_regs * regs, long interruption_code)
 {
         if (regs->psw.mask & PSW_MASK_PSTATE) {
                local_irq_enable();
@@ -376,7 +375,7 @@ default_trap_handler(struct pt_regs * regs, long interruption_code)
 }
 
 #define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
-asmlinkage void name(struct pt_regs * regs, long interruption_code) \
+static void name(struct pt_regs * regs, long interruption_code) \
 { \
         siginfo_t info; \
         info.si_signo = signr; \
@@ -442,7 +441,7 @@ do_fp_trap(struct pt_regs *regs, void __user *location,
                "floating point exception", regs, &si);
 }
 
-asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
+static void illegal_op(struct pt_regs * regs, long interruption_code)
 {
        siginfo_t info;
         __u8 opcode[6];
@@ -491,8 +490,15 @@ asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
 #endif
                } else
                        signal = SIGILL;
-       } else
-               signal = SIGILL;
+       } else {
+               /*
+                * If we get an illegal op in kernel mode, send it through the
+                * kprobes notifier. If kprobes doesn't pick it up, SIGILL
+                */
+               if (notify_die(DIE_BPT, "bpt", regs, interruption_code,
+                              3, SIGTRAP) != NOTIFY_STOP)
+                       signal = SIGILL;
+       }
 
 #ifdef CONFIG_MATHEMU
         if (signal == SIGFPE)
@@ -585,7 +591,7 @@ DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
              ILL_ILLOPN, get_check_address(regs));
 #endif
 
-asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
+static void data_exception(struct pt_regs * regs, long interruption_code)
 {
        __u16 __user *location;
        int signal = 0;
@@ -675,7 +681,7 @@ asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
        }
 }
 
-asmlinkage void space_switch_exception(struct pt_regs * regs, long int_code)
+static void space_switch_exception(struct pt_regs * regs, long int_code)
 {
         siginfo_t info;
 
index fe0f2e9..a489073 100644 (file)
@@ -31,18 +31,19 @@ SECTIONS
 
   _etext = .;                  /* End of text section */
 
-  . = ALIGN(16);               /* Exception table */
-  __start___ex_table = .;
-  __ex_table : { *(__ex_table) }
-  __stop___ex_table = .;
-
   RODATA
 
 #ifdef CONFIG_SHARED_KERNEL
   . = ALIGN(1048576);          /* VM shared segments are 1MB aligned */
+#endif
 
+  . = ALIGN(4096);
   _eshared = .;                        /* End of shareable data */
-#endif
+
+  . = ALIGN(16);               /* Exception table */
+  __start___ex_table = .;
+  __ex_table : { *(__ex_table) }
+  __stop___ex_table = .;
 
   .data : {                    /* Data */
        *(.data)
index 21baaf5..9d5b028 100644 (file)
@@ -25,7 +25,7 @@
 #include <asm/irq_regs.h>
 
 static ext_int_info_t ext_int_info_timer;
-DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
+static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 /*
@@ -524,16 +524,15 @@ EXPORT_SYMBOL(del_virt_timer);
 void init_cpu_vtimer(void)
 {
        struct vtimer_queue *vt_list;
-       unsigned long cr0;
 
        /* kick the virtual timer */
        S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
        S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
        asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
        asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
-       __ctl_store(cr0, 0, 0);
-       cr0 |= 0x400;
-       __ctl_load(cr0, 0, 0);
+
+       /* enable cpu timer interrupts */
+       __ctl_set_bit(0,10);
 
        vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
        INIT_LIST_HEAD(&vt_list->list);
@@ -572,6 +571,7 @@ void __init vtime_init(void)
        if (register_idle_notifier(&vtimer_idle_nb))
                panic("Couldn't register idle notifier");
 
+       /* Enable cpu timer interrupts on the boot cpu. */
        init_cpu_vtimer();
 }
 
index b5f94cf..7a44fed 100644 (file)
@@ -4,7 +4,7 @@
 
 EXTRA_AFLAGS := -traditional
 
-lib-y += delay.o string.o uaccess_std.o uaccess_pt.o
+lib-y += delay.o string.o uaccess_std.o uaccess_pt.o qrnnd.o
 lib-$(CONFIG_32BIT) += div64.o
 lib-$(CONFIG_64BIT) += uaccess_mvcos.o
 lib-$(CONFIG_SMP) += spinlock.o
index 027c474..0285444 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  arch/s390/kernel/delay.c
+ *  arch/s390/lib/delay.c
  *    Precise Delay Loops for S390
  *
  *  S390 version
 
 #include <linux/sched.h>
 #include <linux/delay.h>
-
-#ifdef CONFIG_SMP
-#include <asm/smp.h>
-#endif
+#include <linux/timex.h>
+#include <linux/irqflags.h>
 
 void __delay(unsigned long loops)
 {
@@ -31,17 +29,39 @@ void __delay(unsigned long loops)
 }
 
 /*
- * Waits for 'usecs' microseconds using the tod clock, giving up the time slice
- * of the virtual PU inbetween to avoid congestion.
+ * Waits for 'usecs' microseconds using the TOD clock comparator.
  */
 void __udelay(unsigned long usecs)
 {
-       uint64_t start_cc;
+       u64 end, time, jiffy_timer = 0;
+       unsigned long flags, cr0, mask, dummy;
+
+       local_irq_save(flags);
+       if (raw_irqs_disabled_flags(flags)) {
+               jiffy_timer = S390_lowcore.jiffy_timer;
+               S390_lowcore.jiffy_timer = -1ULL - (4096 << 12);
+               __ctl_store(cr0, 0, 0);
+               dummy = (cr0 & 0xffff00e0) | 0x00000800;
+               __ctl_load(dummy , 0, 0);
+               mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT;
+       } else
+               mask = psw_kernel_bits | PSW_MASK_WAIT |
+                       PSW_MASK_EXT | PSW_MASK_IO;
+
+       end = get_clock() + ((u64) usecs << 12);
+       do {
+               time = end < S390_lowcore.jiffy_timer ?
+                       end : S390_lowcore.jiffy_timer;
+               set_clock_comparator(time);
+               trace_hardirqs_on();
+               __load_psw_mask(mask);
+               local_irq_disable();
+       } while (get_clock() < end);
 
-        if (usecs == 0)
-                return;
-       start_cc = get_clock();
-        do {
-               cpu_relax();
-       } while (((get_clock() - start_cc)/4096) < usecs);
+       if (raw_irqs_disabled_flags(flags)) {
+               __ctl_load(cr0, 0, 0);
+               S390_lowcore.jiffy_timer = jiffy_timer;
+       }
+       set_clock_comparator(S390_lowcore.jiffy_timer);
+       local_irq_restore(flags);
 }
diff --git a/arch/s390/lib/qrnnd.S b/arch/s390/lib/qrnnd.S
new file mode 100644 (file)
index 0000000..eb1df63
--- /dev/null
@@ -0,0 +1,77 @@
+# S/390 __udiv_qrnnd
+
+# r2 : &__r
+# r3 : upper half of 64 bit word n
+# r4 : lower half of 64 bit word n
+# r5 : divisor d
+# the reminder r of the division is to be stored to &__r and
+# the quotient q is to be returned
+
+       .text
+       .globl __udiv_qrnnd
+__udiv_qrnnd:
+       st    %r2,24(%r15)        # store pointer to reminder for later
+       lr    %r0,%r3             # reload n
+       lr    %r1,%r4
+       ltr   %r2,%r5             # reload and test divisor
+       jp    5f
+       # divisor >= 0x80000000
+       srdl  %r0,2               # n/4
+       srl   %r2,1               # d/2
+       slr   %r1,%r2             # special case if last bit of d is set
+       brc   3,0f                #  (n/4) div (n/2) can overflow by 1
+       ahi   %r0,-1              #  trick: subtract n/2, then divide
+0:     dr    %r0,%r2             # signed division
+       ahi   %r1,1               #  trick part 2: add 1 to the quotient
+       # now (n >> 2) = (d >> 1) * %r1 + %r0
+       lhi   %r3,1
+       nr    %r3,%r1             # test last bit of q
+       jz    1f
+       alr   %r0,%r2             # add (d>>1) to r
+1:     srl   %r1,1               # q >>= 1
+       # now (n >> 2) = (d&-2) * %r1 + %r0
+       lhi   %r3,1
+       nr    %r3,%r5             # test last bit of d
+       jz    2f
+       slr   %r0,%r1             # r -= q
+       brc   3,2f                # borrow ?
+       alr   %r0,%r5             # r += d
+       ahi   %r1,-1
+2:     # now (n >> 2) = d * %r1 + %r0
+       alr   %r1,%r1             # q <<= 1
+       alr   %r0,%r0             # r <<= 1
+       brc   12,3f               # overflow on r ?
+       slr   %r0,%r5             # r -= d
+       ahi   %r1,1               # q += 1
+3:     lhi   %r3,2
+       nr    %r3,%r4             # test next to last bit of n
+       jz    4f
+       ahi   %r0,1               # r += 1
+4:     clr   %r0,%r5             # r >= d ?
+       jl    6f
+       slr   %r0,%r5             # r -= d
+       ahi   %r1,1               # q += 1
+       # now (n >> 1) = d * %r1 + %r0
+       j     6f
+5:     # divisor < 0x80000000
+       srdl  %r0,1
+       dr    %r0,%r2             # signed division
+       # now (n >> 1) = d * %r1 + %r0
+6:     alr   %r1,%r1             # q <<= 1
+       alr   %r0,%r0             # r <<= 1
+       brc   12,7f               # overflow on r ?
+       slr   %r0,%r5             # r -= d
+       ahi   %r1,1               # q += 1
+7:     lhi   %r3,1
+       nr    %r3,%r4             # isolate last bit of n
+       alr   %r0,%r3             # r += (n & 1)
+       clr   %r0,%r5             # r >= d ?
+       jl    8f
+       slr   %r0,%r5             # r -= d
+       ahi   %r1,1               # q += 1
+8:     # now n = d * %r1 + %r0
+       l     %r2,24(%r15)
+       st    %r0,0(%r2)
+       lr    %r2,%r1
+       br    %r14
+       .end    __udiv_qrnnd
diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
new file mode 100644 (file)
index 0000000..126011d
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ *  arch/s390/uaccess.h
+ *
+ *    Copyright IBM Corp. 2007
+ *
+ */
+
+#ifndef __ARCH_S390_LIB_UACCESS_H
+#define __ARCH_S390_LIB_UACCESS_H
+
+extern size_t copy_from_user_std(size_t, const void __user *, void *);
+extern size_t copy_to_user_std(size_t, void __user *, const void *);
+extern size_t strnlen_user_std(size_t, const char __user *);
+extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
+extern int futex_atomic_cmpxchg_std(int __user *, int, int);
+extern int futex_atomic_op_std(int, int __user *, int, int *);
+
+extern size_t copy_from_user_pt(size_t, const void __user *, void *);
+extern size_t copy_to_user_pt(size_t, void __user *, const void *);
+extern int futex_atomic_op_pt(int, int __user *, int, int *);
+extern int futex_atomic_cmpxchg_pt(int __user *, int, int);
+
+#endif /* __ARCH_S390_LIB_UACCESS_H */
index f9a23d5..6d87723 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/futex.h>
+#include "uaccess.h"
 
 #ifndef __s390x__
 #define AHI    "ahi"
 #define SLR    "slgr"
 #endif
 
-extern size_t copy_from_user_std(size_t, const void __user *, void *);
-extern size_t copy_to_user_std(size_t, void __user *, const void *);
-
-size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
+static size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
 {
        register unsigned long reg0 asm("0") = 0x81UL;
        unsigned long tmp1, tmp2;
@@ -69,14 +67,14 @@ size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x)
        return size;
 }
 
-size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x)
+static size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x)
 {
        if (size <= 256)
                return copy_from_user_std(size, ptr, x);
        return copy_from_user_mvcos(size, ptr, x);
 }
 
-size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
+static size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
 {
        register unsigned long reg0 asm("0") = 0x810000UL;
        unsigned long tmp1, tmp2;
@@ -105,14 +103,16 @@ size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x)
        return size;
 }
 
-size_t copy_to_user_mvcos_check(size_t size, void __user *ptr, const void *x)
+static size_t copy_to_user_mvcos_check(size_t size, void __user *ptr,
+                                      const void *x)
 {
        if (size <= 256)
                return copy_to_user_std(size, ptr, x);
        return copy_to_user_mvcos(size, ptr, x);
 }
 
-size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from)
+static size_t copy_in_user_mvcos(size_t size, void __user *to,
+                                const void __user *from)
 {
        register unsigned long reg0 asm("0") = 0x810081UL;
        unsigned long tmp1, tmp2;
@@ -134,7 +134,7 @@ size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from)
        return size;
 }
 
-size_t clear_user_mvcos(size_t size, void __user *to)
+static size_t clear_user_mvcos(size_t size, void __user *to)
 {
        register unsigned long reg0 asm("0") = 0x810000UL;
        unsigned long tmp1, tmp2;
@@ -162,10 +162,43 @@ size_t clear_user_mvcos(size_t size, void __user *to)
        return size;
 }
 
-extern size_t strnlen_user_std(size_t, const char __user *);
-extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
-extern int futex_atomic_op(int, int __user *, int, int *);
-extern int futex_atomic_cmpxchg(int __user *, int, int);
+static size_t strnlen_user_mvcos(size_t count, const char __user *src)
+{
+       char buf[256];
+       int rc;
+       size_t done, len, len_str;
+
+       done = 0;
+       do {
+               len = min(count - done, (size_t) 256);
+               rc = uaccess.copy_from_user(len, src + done, buf);
+               if (unlikely(rc == len))
+                       return 0;
+               len -= rc;
+               len_str = strnlen(buf, len);
+               done += len_str;
+       } while ((len_str == len) && (done < count));
+       return done + 1;
+}
+
+static size_t strncpy_from_user_mvcos(size_t count, const char __user *src,
+                                     char *dst)
+{
+       int rc;
+       size_t done, len, len_str;
+
+       done = 0;
+       do {
+               len = min(count - done, (size_t) 4096);
+               rc = uaccess.copy_from_user(len, src + done, dst);
+               if (unlikely(rc == len))
+                       return -EFAULT;
+               len -= rc;
+               len_str = strnlen(dst, len);
+               done += len_str;
+       } while ((len_str == len) && (done < count));
+       return done;
+}
 
 struct uaccess_ops uaccess_mvcos = {
        .copy_from_user = copy_from_user_mvcos_check,
@@ -176,6 +209,21 @@ struct uaccess_ops uaccess_mvcos = {
        .clear_user = clear_user_mvcos,
        .strnlen_user = strnlen_user_std,
        .strncpy_from_user = strncpy_from_user_std,
-       .futex_atomic_op = futex_atomic_op,
-       .futex_atomic_cmpxchg = futex_atomic_cmpxchg,
+       .futex_atomic_op = futex_atomic_op_std,
+       .futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
+};
+
+#ifdef CONFIG_S390_SWITCH_AMODE
+struct uaccess_ops uaccess_mvcos_switch = {
+       .copy_from_user = copy_from_user_mvcos,
+       .copy_from_user_small = copy_from_user_mvcos,
+       .copy_to_user = copy_to_user_mvcos,
+       .copy_to_user_small = copy_to_user_mvcos,
+       .copy_in_user = copy_in_user_mvcos,
+       .clear_user = clear_user_mvcos,
+       .strnlen_user = strnlen_user_mvcos,
+       .strncpy_from_user = strncpy_from_user_mvcos,
+       .futex_atomic_op = futex_atomic_op_pt,
+       .futex_atomic_cmpxchg = futex_atomic_cmpxchg_pt,
 };
+#endif
index 49c3e46..6318167 100644 (file)
@@ -1,7 +1,8 @@
 /*
  *  arch/s390/lib/uaccess_pt.c
  *
- *  User access functions based on page table walks.
+ *  User access functions based on page table walks for enhanced
+ *  system layout without hardware support.
  *
  *    Copyright IBM Corp. 2006
  *    Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com)
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 #include <asm/futex.h>
+#include "uaccess.h"
 
-static inline int __handle_fault(struct mm_struct *mm, unsigned long address,
-                                int write_access)
+static int __handle_fault(struct mm_struct *mm, unsigned long address,
+                         int write_access)
 {
        struct vm_area_struct *vma;
        int ret = -EFAULT;
@@ -79,8 +81,8 @@ out_sigbus:
        return ret;
 }
 
-static inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
-                                   size_t n, int write_user)
+static size_t __user_copy_pt(unsigned long uaddr, void *kptr,
+                            size_t n, int write_user)
 {
        struct mm_struct *mm = current->mm;
        unsigned long offset, pfn, done, size;
@@ -133,6 +135,49 @@ fault:
        goto retry;
 }
 
+/*
+ * Do DAT for user address by page table walk, return kernel address.
+ * This function needs to be called with current->mm->page_table_lock held.
+ */
+static unsigned long __dat_user_addr(unsigned long uaddr)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long pfn, ret;
+       pgd_t *pgd;
+       pmd_t *pmd;
+       pte_t *pte;
+       int rc;
+
+       ret = 0;
+retry:
+       pgd = pgd_offset(mm, uaddr);
+       if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+               goto fault;
+
+       pmd = pmd_offset(pgd, uaddr);
+       if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+               goto fault;
+
+       pte = pte_offset_map(pmd, uaddr);
+       if (!pte || !pte_present(*pte))
+               goto fault;
+
+       pfn = pte_pfn(*pte);
+       if (!pfn_valid(pfn))
+               goto out;
+
+       ret = (pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE - 1));
+out:
+       return ret;
+fault:
+       spin_unlock(&mm->page_table_lock);
+       rc = __handle_fault(mm, uaddr, 0);
+       spin_lock(&mm->page_table_lock);
+       if (rc)
+               goto out;
+       goto retry;
+}
+
 size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
 {
        size_t rc;
@@ -155,3 +200,277 @@ size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
        }
        return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
 }
+
+static size_t clear_user_pt(size_t n, void __user *to)
+{
+       long done, size, ret;
+
+       if (segment_eq(get_fs(), KERNEL_DS)) {
+               memset((void __kernel __force *) to, 0, n);
+               return 0;
+       }
+       done = 0;
+       do {
+               if (n - done > PAGE_SIZE)
+                       size = PAGE_SIZE;
+               else
+                       size = n - done;
+               ret = __user_copy_pt((unsigned long) to + done,
+                                     &empty_zero_page, size, 1);
+               done += size;
+               if (ret)
+                       return ret + n - done;
+       } while (done < n);
+       return 0;
+}
+
+static size_t strnlen_user_pt(size_t count, const char __user *src)
+{
+       char *addr;
+       unsigned long uaddr = (unsigned long) src;
+       struct mm_struct *mm = current->mm;
+       unsigned long offset, pfn, done, len;
+       pgd_t *pgd;
+       pmd_t *pmd;
+       pte_t *pte;
+       size_t len_str;
+
+       if (segment_eq(get_fs(), KERNEL_DS))
+               return strnlen((const char __kernel __force *) src, count) + 1;
+       done = 0;
+retry:
+       spin_lock(&mm->page_table_lock);
+       do {
+               pgd = pgd_offset(mm, uaddr);
+               if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+                       goto fault;
+
+               pmd = pmd_offset(pgd, uaddr);
+               if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+                       goto fault;
+
+               pte = pte_offset_map(pmd, uaddr);
+               if (!pte || !pte_present(*pte))
+                       goto fault;
+
+               pfn = pte_pfn(*pte);
+               if (!pfn_valid(pfn)) {
+                       done = -1;
+                       goto out;
+               }
+
+               offset = uaddr & (PAGE_SIZE-1);
+               addr = (char *)(pfn << PAGE_SHIFT) + offset;
+               len = min(count - done, PAGE_SIZE - offset);
+               len_str = strnlen(addr, len);
+               done += len_str;
+               uaddr += len_str;
+       } while ((len_str == len) && (done < count));
+out:
+       spin_unlock(&mm->page_table_lock);
+       return done + 1;
+fault:
+       spin_unlock(&mm->page_table_lock);
+       if (__handle_fault(mm, uaddr, 0)) {
+               return 0;
+       }
+       goto retry;
+}
+
+static size_t strncpy_from_user_pt(size_t count, const char __user *src,
+                                  char *dst)
+{
+       size_t n = strnlen_user_pt(count, src);
+
+       if (!n)
+               return -EFAULT;
+       if (n > count)
+               n = count;
+       if (segment_eq(get_fs(), KERNEL_DS)) {
+               memcpy(dst, (const char __kernel __force *) src, n);
+               if (dst[n-1] == '\0')
+                       return n-1;
+               else
+                       return n;
+       }
+       if (__user_copy_pt((unsigned long) src, dst, n, 0))
+               return -EFAULT;
+       if (dst[n-1] == '\0')
+               return n-1;
+       else
+               return n;
+}
+
+static size_t copy_in_user_pt(size_t n, void __user *to,
+                             const void __user *from)
+{
+       struct mm_struct *mm = current->mm;
+       unsigned long offset_from, offset_to, offset_max, pfn_from, pfn_to,
+                     uaddr, done, size;
+       unsigned long uaddr_from = (unsigned long) from;
+       unsigned long uaddr_to = (unsigned long) to;
+       pgd_t *pgd_from, *pgd_to;
+       pmd_t *pmd_from, *pmd_to;
+       pte_t *pte_from, *pte_to;
+       int write_user;
+
+       done = 0;
+retry:
+       spin_lock(&mm->page_table_lock);
+       do {
+               pgd_from = pgd_offset(mm, uaddr_from);
+               if (pgd_none(*pgd_from) || unlikely(pgd_bad(*pgd_from))) {
+                       uaddr = uaddr_from;
+                       write_user = 0;
+                       goto fault;
+               }
+               pgd_to = pgd_offset(mm, uaddr_to);
+               if (pgd_none(*pgd_to) || unlikely(pgd_bad(*pgd_to))) {
+                       uaddr = uaddr_to;
+                       write_user = 1;
+                       goto fault;
+               }
+
+               pmd_from = pmd_offset(pgd_from, uaddr_from);
+               if (pmd_none(*pmd_from) || unlikely(pmd_bad(*pmd_from))) {
+                       uaddr = uaddr_from;
+                       write_user = 0;
+                       goto fault;
+               }
+               pmd_to = pmd_offset(pgd_to, uaddr_to);
+               if (pmd_none(*pmd_to) || unlikely(pmd_bad(*pmd_to))) {
+                       uaddr = uaddr_to;
+                       write_user = 1;
+                       goto fault;
+               }
+
+               pte_from = pte_offset_map(pmd_from, uaddr_from);
+               if (!pte_from || !pte_present(*pte_from)) {
+                       uaddr = uaddr_from;
+                       write_user = 0;
+                       goto fault;
+               }
+               pte_to = pte_offset_map(pmd_to, uaddr_to);
+               if (!pte_to || !pte_present(*pte_to) || !pte_write(*pte_to)) {
+                       uaddr = uaddr_to;
+                       write_user = 1;
+                       goto fault;
+               }
+
+               pfn_from = pte_pfn(*pte_from);
+               if (!pfn_valid(pfn_from))
+                       goto out;
+               pfn_to = pte_pfn(*pte_to);
+               if (!pfn_valid(pfn_to))
+                       goto out;
+
+               offset_from = uaddr_from & (PAGE_SIZE-1);
+               offset_to = uaddr_from & (PAGE_SIZE-1);
+               offset_max = max(offset_from, offset_to);
+               size = min(n - done, PAGE_SIZE - offset_max);
+
+               memcpy((void *)(pfn_to << PAGE_SHIFT) + offset_to,
+                      (void *)(pfn_from << PAGE_SHIFT) + offset_from, size);
+               done += size;
+               uaddr_from += size;
+               uaddr_to += size;
+       } while (done < n);
+out:
+       spin_unlock(&mm->page_table_lock);
+       return n - done;
+fault:
+       spin_unlock(&mm->page_table_lock);
+       if (__handle_fault(mm, uaddr, write_user))
+               return n - done;
+       goto retry;
+}
+
+#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg)     \
+       asm volatile("0: l   %1,0(%6)\n"                                \
+                    "1: " insn                                         \
+                    "2: cs  %1,%2,0(%6)\n"                             \
+                    "3: jl  1b\n"                                      \
+                    "   lhi %0,0\n"                                    \
+                    "4:\n"                                             \
+                    EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b)    \
+                    : "=d" (ret), "=&d" (oldval), "=&d" (newval),      \
+                      "=m" (*uaddr)                                    \
+                    : "0" (-EFAULT), "d" (oparg), "a" (uaddr),         \
+                      "m" (*uaddr) : "cc" );
+
+int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+{
+       int oldval = 0, newval, ret;
+
+       spin_lock(&current->mm->page_table_lock);
+       uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
+       if (!uaddr) {
+               spin_unlock(&current->mm->page_table_lock);
+               return -EFAULT;
+       }
+       get_page(virt_to_page(uaddr));
+       spin_unlock(&current->mm->page_table_lock);
+       switch (op) {
+       case FUTEX_OP_SET:
+               __futex_atomic_op("lr %2,%5\n",
+                                 ret, oldval, newval, uaddr, oparg);
+               break;
+       case FUTEX_OP_ADD:
+               __futex_atomic_op("lr %2,%1\nar %2,%5\n",
+                                 ret, oldval, newval, uaddr, oparg);
+               break;
+       case FUTEX_OP_OR:
+               __futex_atomic_op("lr %2,%1\nor %2,%5\n",
+                                 ret, oldval, newval, uaddr, oparg);
+               break;
+       case FUTEX_OP_ANDN:
+               __futex_atomic_op("lr %2,%1\nnr %2,%5\n",
+                                 ret, oldval, newval, uaddr, oparg);
+               break;
+       case FUTEX_OP_XOR:
+               __futex_atomic_op("lr %2,%1\nxr %2,%5\n",
+                                 ret, oldval, newval, uaddr, oparg);
+               break;
+       default:
+               ret = -ENOSYS;
+       }
+       put_page(virt_to_page(uaddr));
+       *old = oldval;
+       return ret;
+}
+
+int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+{
+       int ret;
+
+       spin_lock(&current->mm->page_table_lock);
+       uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
+       if (!uaddr) {
+               spin_unlock(&current->mm->page_table_lock);
+               return -EFAULT;
+       }
+       get_page(virt_to_page(uaddr));
+       spin_unlock(&current->mm->page_table_lock);
+       asm volatile("   cs   %1,%4,0(%5)\n"
+                    "0: lr   %0,%1\n"
+                    "1:\n"
+                    EX_TABLE(0b,1b)
+                    : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
+                    : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
+                    : "cc", "memory" );
+       put_page(virt_to_page(uaddr));
+       return ret;
+}
+
+struct uaccess_ops uaccess_pt = {
+       .copy_from_user         = copy_from_user_pt,
+       .copy_from_user_small   = copy_from_user_pt,
+       .copy_to_user           = copy_to_user_pt,
+       .copy_to_user_small     = copy_to_user_pt,
+       .copy_in_user           = copy_in_user_pt,
+       .clear_user             = clear_user_pt,
+       .strnlen_user           = strnlen_user_pt,
+       .strncpy_from_user      = strncpy_from_user_pt,
+       .futex_atomic_op        = futex_atomic_op_pt,
+       .futex_atomic_cmpxchg   = futex_atomic_cmpxchg_pt,
+};
index 56a0214..28c4500 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/mm.h>
 #include <linux/uaccess.h>
 #include <asm/futex.h>
+#include "uaccess.h"
 
 #ifndef __s390x__
 #define AHI    "ahi"
@@ -28,9 +29,6 @@
 #define SLR    "slgr"
 #endif
 
-extern size_t copy_from_user_pt(size_t n, const void __user *from, void *to);
-extern size_t copy_to_user_pt(size_t n, void __user *to, const void *from);
-
 size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
 {
        unsigned long tmp1, tmp2;
@@ -72,7 +70,8 @@ size_t copy_from_user_std(size_t size, const void __user *ptr, void *x)
        return size;
 }
 
-size_t copy_from_user_std_check(size_t size, const void __user *ptr, void *x)
+static size_t copy_from_user_std_check(size_t size, const void __user *ptr,
+                                      void *x)
 {
        if (size <= 1024)
                return copy_from_user_std(size, ptr, x);
@@ -110,14 +109,16 @@ size_t copy_to_user_std(size_t size, void __user *ptr, const void *x)
        return size;
 }
 
-size_t copy_to_user_std_check(size_t size, void __user *ptr, const void *x)
+static size_t copy_to_user_std_check(size_t size, void __user *ptr,
+                                    const void *x)
 {
        if (size <= 1024)
                return copy_to_user_std(size, ptr, x);
        return copy_to_user_pt(size, ptr, x);
 }
 
-size_t copy_in_user_std(size_t size, void __user *to, const void __user *from)
+static size_t copy_in_user_std(size_t size, void __user *to,
+                              const void __user *from)
 {
        unsigned long tmp1;
 
@@ -148,7 +149,7 @@ size_t copy_in_user_std(size_t size, void __user *to, const void __user *from)
        return size;
 }
 
-size_t clear_user_std(size_t size, void __user *to)
+static size_t clear_user_std(size_t size, void __user *to)
 {
        unsigned long tmp1, tmp2;
 
@@ -254,7 +255,7 @@ size_t strncpy_from_user_std(size_t size, const char __user *src, char *dst)
                : "0" (-EFAULT), "d" (oparg), "a" (uaddr),              \
                  "m" (*uaddr) : "cc");
 
-int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old)
+int futex_atomic_op_std(int op, int __user *uaddr, int oparg, int *old)
 {
        int oldval = 0, newval, ret;
 
@@ -286,7 +287,7 @@ int futex_atomic_op(int op, int __user *uaddr, int oparg, int *old)
        return ret;
 }
 
-int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval)
+int futex_atomic_cmpxchg_std(int __user *uaddr, int oldval, int newval)
 {
        int ret;
 
@@ -311,6 +312,6 @@ struct uaccess_ops uaccess_std = {
        .clear_user = clear_user_std,
        .strnlen_user = strnlen_user_std,
        .strncpy_from_user = strncpy_from_user_std,
-       .futex_atomic_op = futex_atomic_op,
-       .futex_atomic_cmpxchg = futex_atomic_cmpxchg,
+       .futex_atomic_op = futex_atomic_op_std,
+       .futex_atomic_cmpxchg = futex_atomic_cmpxchg_std,
 };
index c10df14..73b3e72 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the FPU instruction emulation.
 #
 
-obj-$(CONFIG_MATHEMU) := math.o qrnnd.o
+obj-$(CONFIG_MATHEMU) := math.o
 
 EXTRA_CFLAGS := -I$(src) -Iinclude/math-emu -w
 EXTRA_AFLAGS := -traditional
index 6b9aec5..3ee78cc 100644 (file)
@@ -15,7 +15,7 @@
 #include <asm/uaccess.h>
 #include <asm/lowcore.h>
 
-#include "sfp-util.h"
+#include <asm/sfp-util.h>
 #include <math-emu/soft-fp.h>
 #include <math-emu/single.h>
 #include <math-emu/double.h>
diff --git a/arch/s390/math-emu/qrnnd.S b/arch/s390/math-emu/qrnnd.S
deleted file mode 100644 (file)
index b01c2b6..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-# S/390 __udiv_qrnnd
-
-# r2 : &__r
-# r3 : upper half of 64 bit word n
-# r4 : lower half of 64 bit word n
-# r5 : divisor d
-# the reminder r of the division is to be stored to &__r and
-# the quotient q is to be returned
-
-        .text
-        .globl __udiv_qrnnd
-__udiv_qrnnd:
-        st    %r2,24(%r15)        # store pointer to reminder for later
-        lr    %r0,%r3             # reload n
-       lr    %r1,%r4
-       ltr   %r2,%r5             # reload and test divisor
-        jp    5f
-        # divisor >= 0x80000000
-       srdl  %r0,2               # n/4
-        srl   %r2,1               # d/2
-        slr   %r1,%r2             # special case if last bit of d is set
-        brc   3,0f                #  (n/4) div (n/2) can overflow by 1
-        ahi   %r0,-1              #  trick: subtract n/2, then divide
-0:      dr    %r0,%r2             # signed division
-        ahi   %r1,1               #  trick part 2: add 1 to the quotient
-        # now (n >> 2) = (d >> 1) * %r1 + %r0
-       lhi   %r3,1
-        nr    %r3,%r1             # test last bit of q
-        jz    1f
-        alr   %r0,%r2             # add (d>>1) to r
-1:      srl   %r1,1               # q >>= 1
-        # now (n >> 2) = (d&-2) * %r1 + %r0
-        lhi   %r3,1
-        nr    %r3,%r5             # test last bit of d
-        jz    2f
-        slr   %r0,%r1             # r -= q
-       brc   3,2f                # borrow ?
-       alr   %r0,%r5             # r += d
-       ahi   %r1,-1
-2:      # now (n >> 2) = d * %r1 + %r0
-        alr   %r1,%r1             # q <<= 1
-        alr   %r0,%r0             # r <<= 1
-        brc   12,3f               # overflow on r ?
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-3:      lhi   %r3,2
-        nr    %r3,%r4             # test next to last bit of n
-        jz    4f
-        ahi   %r0,1               # r += 1
-4:      clr   %r0,%r5             # r >= d ?
-        jl    6f
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-        # now (n >> 1) = d * %r1 + %r0
-        j     6f
-5:      # divisor < 0x80000000
-       srdl  %r0,1
-        dr    %r0,%r2             # signed division
-        # now (n >> 1) = d * %r1 + %r0
-6:      alr   %r1,%r1             # q <<= 1
-        alr   %r0,%r0             # r <<= 1
-        brc   12,7f               # overflow on r ?
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-7:      lhi   %r3,1
-        nr    %r3,%r4             # isolate last bit of n
-        alr   %r0,%r3             # r += (n & 1)
-        clr   %r0,%r5             # r >= d ?
-        jl    8f
-        slr   %r0,%r5             # r -= d
-        ahi   %r1,1               # q += 1
-8:      # now n = d * %r1 + %r0
-       l     %r2,24(%r15)
-        st    %r0,0(%r2)
-        lr    %r2,%r1
-        br    %r14
-       .end    __udiv_qrnnd
diff --git a/arch/s390/math-emu/sfp-util.h b/arch/s390/math-emu/sfp-util.h
deleted file mode 100644 (file)
index 5b6ca45..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <asm/byteorder.h>
-
-#define add_ssaaaa(sh, sl, ah, al, bh, bl) ({          \
-       unsigned int __sh = (ah);                       \
-       unsigned int __sl = (al);                       \
-       asm volatile(                                   \
-               "       alr     %1,%3\n"                \
-               "       brc     12,0f\n"                \
-               "       ahi     %0,1\n"                 \
-               "0:     alr  %0,%2"                     \
-               : "+&d" (__sh), "+d" (__sl)             \
-               : "d" (bh), "d" (bl) : "cc");           \
-       (sh) = __sh;                                    \
-       (sl) = __sl;                                    \
-})
-
-#define sub_ddmmss(sh, sl, ah, al, bh, bl) ({          \
-       unsigned int __sh = (ah);                       \
-       unsigned int __sl = (al);                       \
-       asm volatile(                                   \
-               "       slr     %1,%3\n"                \
-               "       brc     3,0f\n"                 \
-               "       ahi     %0,-1\n"                \
-               "0:     slr     %0,%2"                  \
-               : "+&d" (__sh), "+d" (__sl)             \
-               : "d" (bh), "d" (bl) : "cc");           \
-       (sh) = __sh;                                    \
-       (sl) = __sl;                                    \
-})
-
-/* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */
-#define umul_ppmm(wh, wl, u, v) ({                     \
-       unsigned int __wh = u;                          \
-       unsigned int __wl = v;                          \
-       asm volatile(                                   \
-               "       ltr     1,%0\n"                 \
-               "       mr      0,%1\n"                 \
-               "       jnm     0f\n"                           \
-               "       alr     0,%1\n"                 \
-               "0:     ltr     %1,%1\n"                        \
-               "       jnm     1f\n"                           \
-               "       alr     0,%0\n"                 \
-               "1:     lr      %0,0\n"                 \
-               "       lr      %1,1\n"                 \
-               : "+d" (__wh), "+d" (__wl)              \
-               : : "0", "1", "cc");                    \
-       wh = __wh;                                      \
-       wl = __wl;                                      \
-})
-
-#define udiv_qrnnd(q, r, n1, n0, d)                    \
-  do { unsigned long __r;                              \
-    (q) = __udiv_qrnnd (&__r, (n1), (n0), (d));                \
-    (r) = __r;                                         \
-  } while (0)
-extern unsigned long __udiv_qrnnd (unsigned long *, unsigned long,
-                                  unsigned long , unsigned long);
-
-#define UDIV_NEEDS_NORMALIZATION 0
-
-#define abort() return 0
-
-#define __BYTE_ORDER __BIG_ENDIAN
index 607f50e..f93a056 100644 (file)
@@ -245,7 +245,7 @@ cmm_set_timeout(long nr, long seconds)
        cmm_set_timer();
 }
 
-static inline int
+static int
 cmm_skip_blanks(char *cp, char **endp)
 {
        char *str;
@@ -414,7 +414,7 @@ cmm_smsg_target(char *from, char *msg)
 }
 #endif
 
-struct ctl_table_header *cmm_sysctl_header;
+static struct ctl_table_header *cmm_sysctl_header;
 
 static int
 cmm_init (void)
index 775bf19..394980b 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/module.h>
 #include <linux/bootmem.h>
 #include <linux/ctype.h>
+#include <linux/ioport.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/ebcdic.h>
@@ -70,6 +71,7 @@ struct qin64 {
 struct dcss_segment {
        struct list_head list;
        char dcss_name[8];
+       char res_name[15];
        unsigned long start_addr;
        unsigned long end;
        atomic_t ref_count;
@@ -77,6 +79,7 @@ struct dcss_segment {
        unsigned int vm_segtype;
        struct qrange range[6];
        int segcnt;
+       struct resource *res;
 };
 
 static DEFINE_MUTEX(dcss_lock);
@@ -88,7 +91,7 @@ static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC",
  * Create the 8 bytes, ebcdic VM segment name from
  * an ascii name.
  */
-static void inline
+static void
 dcss_mkname(char *name, char *dcss_name)
 {
        int i;
@@ -303,6 +306,29 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
                goto out_free;
        }
 
+       seg->res = kzalloc(sizeof(struct resource), GFP_KERNEL);
+       if (seg->res == NULL) {
+               rc = -ENOMEM;
+               goto out_shared;
+       }
+       seg->res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
+       seg->res->start = seg->start_addr;
+       seg->res->end = seg->end;
+       memcpy(&seg->res_name, seg->dcss_name, 8);
+       EBCASC(seg->res_name, 8);
+       seg->res_name[8] = '\0';
+       strncat(seg->res_name, " (DCSS)", 7);
+       seg->res->name = seg->res_name;
+       rc = seg->vm_segtype;
+       if (rc == SEG_TYPE_SC ||
+           ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared))
+               seg->res->flags |= IORESOURCE_READONLY;
+       if (request_resource(&iomem_resource, seg->res)) {
+               rc = -EBUSY;
+               kfree(seg->res);
+               goto out_shared;
+       }
+
        if (do_nonshared)
                dcss_command = DCSS_LOADNSR;
        else
@@ -316,12 +342,11 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
                rc = dcss_diag_translate_rc (seg->end);
                dcss_diag(DCSS_PURGESEG, seg->dcss_name,
                                &seg->start_addr, &seg->end);
-               goto out_shared;
+               goto out_resource;
        }
        seg->do_nonshared = do_nonshared;
        atomic_set(&seg->ref_count, 1);
        list_add(&seg->list, &dcss_list);
-       rc = seg->vm_segtype;
        *addr = seg->start_addr;
        *end  = seg->end;
        if (do_nonshared)
@@ -329,12 +354,16 @@ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long
                                "type %s in non-shared mode\n", name,
                                (void*)seg->start_addr, (void*)seg->end,
                                segtype_string[seg->vm_segtype]);
-       else
+       else {
                PRINT_INFO ("segment_load: loaded segment %s range %p .. %p "
                                "type %s in shared mode\n", name,
                                (void*)seg->start_addr, (void*)seg->end,
                                segtype_string[seg->vm_segtype]);
+       }
        goto out;
+ out_resource:
+       release_resource(seg->res);
+       kfree(seg->res);
  out_shared:
        remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
  out_free:
@@ -401,6 +430,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr,
  * -ENOENT  : no such segment (segment gone!)
  * -EAGAIN  : segment is in use by other exploiters, try later
  * -EINVAL  : no segment with the given name is currently loaded - name invalid
+ * -EBUSY   : segment can temporarily not be used (overlaps with dcss)
  * 0       : operation succeeded
  */
 int
@@ -428,12 +458,24 @@ segment_modify_shared (char *name, int do_nonshared)
                rc = -EAGAIN;
                goto out_unlock;
        }
-       dcss_diag(DCSS_PURGESEG, seg->dcss_name,
-                 &dummy, &dummy);
-       if (do_nonshared)
+       release_resource(seg->res);
+       if (do_nonshared) {
                dcss_command = DCSS_LOADNSR;
-       else
-       dcss_command = DCSS_LOADNOLY;
+               seg->res->flags &= ~IORESOURCE_READONLY;
+       } else {
+               dcss_command = DCSS_LOADNOLY;
+               if (seg->vm_segtype == SEG_TYPE_SR ||
+                   seg->vm_segtype == SEG_TYPE_ER)
+                       seg->res->flags |= IORESOURCE_READONLY;
+       }
+       if (request_resource(&iomem_resource, seg->res)) {
+               PRINT_WARN("segment_modify_shared: could not reload segment %s"
+                          " - overlapping resources\n", name);
+               rc = -EBUSY;
+               kfree(seg->res);
+               goto out_del;
+       }
+       dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
        diag_cc = dcss_diag(dcss_command, seg->dcss_name,
                        &seg->start_addr, &seg->end);
        if (diag_cc > 1) {
@@ -446,9 +488,9 @@ segment_modify_shared (char *name, int do_nonshared)
        rc = 0;
        goto out_unlock;
  out_del:
+       remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
        list_del(&seg->list);
-       dcss_diag(DCSS_PURGESEG, seg->dcss_name,
-                 &dummy, &dummy);
+       dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
        kfree(seg);
  out_unlock:
        mutex_unlock(&dcss_lock);
@@ -478,6 +520,8 @@ segment_unload(char *name)
        }
        if (atomic_dec_return(&seg->ref_count) != 0)
                goto out_unlock;
+       release_resource(seg->res);
+       kfree(seg->res);
        remove_shared_memory(seg->start_addr, seg->end - seg->start_addr + 1);
        list_del(&seg->list);
        dcss_diag(DCSS_PURGESEG, seg->dcss_name, &dummy, &dummy);
index cd85e34..9ff143e 100644 (file)
@@ -52,7 +52,7 @@ extern int sysctl_userprocess_debug;
 extern void die(const char *,struct pt_regs *,long);
 
 #ifdef CONFIG_KPROBES
-ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
+static ATOMIC_NOTIFIER_HEAD(notify_page_fault_chain);
 int register_page_fault_notifier(struct notifier_block *nb)
 {
        return atomic_notifier_chain_register(&notify_page_fault_chain, nb);
@@ -137,7 +137,9 @@ static int __check_access_register(struct pt_regs *regs, int error_code)
 
 /*
  * Check which address space the address belongs to.
- * Returns 1 for user space and 0 for kernel space.
+ * May return 1 or 2 for user space and 0 for kernel space.
+ * Returns 2 for user space in primary addressing mode with
+ * CONFIG_S390_EXEC_PROTECT on and kernel parameter noexec=on.
  */
 static inline int check_user_space(struct pt_regs *regs, int error_code)
 {
@@ -154,7 +156,7 @@ static inline int check_user_space(struct pt_regs *regs, int error_code)
                return __check_access_register(regs, error_code);
        if (descriptor == 2)
                return current->thread.mm_segment.ar4;
-       return descriptor != 0;
+       return ((descriptor != 0) ^ (switch_amode)) << s390_noexec;
 }
 
 /*
@@ -183,6 +185,77 @@ static void do_sigsegv(struct pt_regs *regs, unsigned long error_code,
        force_sig_info(SIGSEGV, &si, current);
 }
 
+#ifdef CONFIG_S390_EXEC_PROTECT
+extern long sys_sigreturn(struct pt_regs *regs);
+extern long sys_rt_sigreturn(struct pt_regs *regs);
+extern long sys32_sigreturn(struct pt_regs *regs);
+extern long sys32_rt_sigreturn(struct pt_regs *regs);
+
+static inline void do_sigreturn(struct mm_struct *mm, struct pt_regs *regs,
+                               int rt)
+{
+       up_read(&mm->mmap_sem);
+       clear_tsk_thread_flag(current, TIF_SINGLE_STEP);
+#ifdef CONFIG_COMPAT
+       if (test_tsk_thread_flag(current, TIF_31BIT)) {
+               if (rt)
+                       sys32_rt_sigreturn(regs);
+               else
+                       sys32_sigreturn(regs);
+               return;
+       }
+#endif /* CONFIG_COMPAT */
+       if (rt)
+               sys_rt_sigreturn(regs);
+       else
+               sys_sigreturn(regs);
+       return;
+}
+
+static int signal_return(struct mm_struct *mm, struct pt_regs *regs,
+                        unsigned long address, unsigned long error_code)
+{
+       pgd_t *pgd;
+       pmd_t *pmd;
+       pte_t *pte;
+       u16 *instruction;
+       unsigned long pfn, uaddr = regs->psw.addr;
+
+       spin_lock(&mm->page_table_lock);
+       pgd = pgd_offset(mm, uaddr);
+       if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd)))
+               goto out_fault;
+       pmd = pmd_offset(pgd, uaddr);
+       if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+               goto out_fault;
+       pte = pte_offset_map(pmd_offset(pgd_offset(mm, uaddr), uaddr), uaddr);
+       if (!pte || !pte_present(*pte))
+               goto out_fault;
+       pfn = pte_pfn(*pte);
+       if (!pfn_valid(pfn))
+               goto out_fault;
+       spin_unlock(&mm->page_table_lock);
+
+       instruction = (u16 *) ((pfn << PAGE_SHIFT) + (uaddr & (PAGE_SIZE-1)));
+       if (*instruction == 0x0a77)
+               do_sigreturn(mm, regs, 0);
+       else if (*instruction == 0x0aad)
+               do_sigreturn(mm, regs, 1);
+       else {
+               printk("- XXX - do_exception: task = %s, primary, NO EXEC "
+                      "-> SIGSEGV\n", current->comm);
+               up_read(&mm->mmap_sem);
+               current->thread.prot_addr = address;
+               current->thread.trap_no = error_code;
+               do_sigsegv(regs, error_code, SEGV_MAPERR, address);
+       }
+       return 0;
+out_fault:
+       spin_unlock(&mm->page_table_lock);
+       return -EFAULT;
+}
+#endif /* CONFIG_S390_EXEC_PROTECT */
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -260,6 +333,17 @@ do_exception(struct pt_regs *regs, unsigned long error_code, int is_protection)
         vma = find_vma(mm, address);
         if (!vma)
                 goto bad_area;
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+       if (unlikely((user_address == 2) && !(vma->vm_flags & VM_EXEC)))
+               if (!signal_return(mm, regs, address, error_code))
+                       /*
+                        * signal_return() has done an up_read(&mm->mmap_sem)
+                        * if it returns 0.
+                        */
+                       return;
+#endif
+
         if (vma->vm_start <= address) 
                 goto good_area;
         if (!(vma->vm_flags & VM_GROWSDOWN))
@@ -452,8 +536,7 @@ void pfault_fini(void)
                : : "a" (&refbk), "m" (refbk) : "cc");
 }
 
-asmlinkage void
-pfault_interrupt(__u16 error_code)
+static void pfault_interrupt(__u16 error_code)
 {
        struct task_struct *tsk;
        __u16 subcode;
index 4bb21be..b3e7c45 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/bootmem.h>
 #include <linux/pfn.h>
 #include <linux/poison.h>
-
+#include <linux/initrd.h>
 #include <asm/processor.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
@@ -95,20 +95,18 @@ static void __init setup_ro_region(void)
        pte_t new_pte;
        unsigned long address, end;
 
-       address = ((unsigned long)&__start_rodata) & PAGE_MASK;
-       end = PFN_ALIGN((unsigned long)&__end_rodata);
+       address = ((unsigned long)&_stext) & PAGE_MASK;
+       end = PFN_ALIGN((unsigned long)&_eshared);
 
        for (; address < end; address += PAGE_SIZE) {
                pgd = pgd_offset_k(address);
                pmd = pmd_offset(pgd, address);
                pte = pte_offset_kernel(pmd, address);
                new_pte = mk_pte_phys(address, __pgprot(_PAGE_RO));
-               set_pte(pte, new_pte);
+               *pte = new_pte;
        }
 }
 
-extern void vmem_map_init(void);
-
 /*
  * paging_init() sets up the page tables
  */
@@ -125,11 +123,11 @@ void __init paging_init(void)
 #ifdef CONFIG_64BIT
        pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERN_REGION_TABLE;
        for (i = 0; i < PTRS_PER_PGD; i++)
-               pgd_clear(pg_dir + i);
+               pgd_clear_kernel(pg_dir + i);
 #else
        pgdir_k = (__pa(swapper_pg_dir) & PAGE_MASK) | _KERNSEG_TABLE;
        for (i = 0; i < PTRS_PER_PGD; i++)
-               pmd_clear((pmd_t *)(pg_dir + i));
+               pmd_clear_kernel((pmd_t *)(pg_dir + i));
 #endif
        vmem_map_init();
        setup_ro_region();
@@ -174,10 +172,8 @@ void __init mem_init(void)
                 datasize >>10,
                 initsize >> 10);
        printk("Write protected kernel read-only data: %#lx - %#lx\n",
-              (unsigned long)&__start_rodata,
-              PFN_ALIGN((unsigned long)&__end_rodata) - 1);
-       printk("Virtual memmap size: %ldk\n",
-              (max_pfn * sizeof(struct page)) >> 10);
+              (unsigned long)&_stext,
+              PFN_ALIGN((unsigned long)&_eshared) - 1);
 }
 
 void free_initmem(void)
index cd3d93e..92a5651 100644 (file)
@@ -82,7 +82,7 @@ static inline pmd_t *vmem_pmd_alloc(void)
        if (!pmd)
                return NULL;
        for (i = 0; i < PTRS_PER_PMD; i++)
-               pmd_clear(pmd + i);
+               pmd_clear_kernel(pmd + i);
        return pmd;
 }
 
@@ -97,7 +97,7 @@ static inline pte_t *vmem_pte_alloc(void)
                return NULL;
        pte_val(empty_pte) = _PAGE_TYPE_EMPTY;
        for (i = 0; i < PTRS_PER_PTE; i++)
-               set_pte(pte + i, empty_pte);
+               pte[i] = empty_pte;
        return pte;
 }
 
@@ -119,7 +119,7 @@ static int vmem_add_range(unsigned long start, unsigned long size)
                        pm_dir = vmem_pmd_alloc();
                        if (!pm_dir)
                                goto out;
-                       pgd_populate(&init_mm, pg_dir, pm_dir);
+                       pgd_populate_kernel(&init_mm, pg_dir, pm_dir);
                }
 
                pm_dir = pmd_offset(pg_dir, address);
@@ -132,7 +132,7 @@ static int vmem_add_range(unsigned long start, unsigned long size)
 
                pt_dir = pte_offset_kernel(pm_dir, address);
                pte = pfn_pte(address >> PAGE_SHIFT, PAGE_KERNEL);
-               set_pte(pt_dir, pte);
+               *pt_dir = pte;
        }
        ret = 0;
 out:
@@ -161,7 +161,7 @@ static void vmem_remove_range(unsigned long start, unsigned long size)
                if (pmd_none(*pm_dir))
                        continue;
                pt_dir = pte_offset_kernel(pm_dir, address);
-               set_pte(pt_dir, pte);
+               *pt_dir = pte;
        }
        flush_tlb_kernel_range(start, start + size);
 }
@@ -191,7 +191,7 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size)
                        pm_dir = vmem_pmd_alloc();
                        if (!pm_dir)
                                goto out;
-                       pgd_populate(&init_mm, pg_dir, pm_dir);
+                       pgd_populate_kernel(&init_mm, pg_dir, pm_dir);
                }
 
                pm_dir = pmd_offset(pg_dir, address);
@@ -210,7 +210,7 @@ static int vmem_add_mem_map(unsigned long start, unsigned long size)
                        if (!new_page)
                                goto out;
                        pte = pfn_pte(new_page >> PAGE_SHIFT, PAGE_KERNEL);
-                       set_pte(pt_dir, pte);
+                       *pt_dir = pte;
                }
        }
        ret = 0;
index 49802f1..bd30d13 100644 (file)
@@ -32,7 +32,7 @@ static void via_bugs(void)
 
 static int nvidia_hpet_detected __initdata;
 
-static int __init nvidia_hpet_check(unsigned long phys, unsigned long size)
+static int __init nvidia_hpet_check(struct acpi_table_header *header)
 {
        nvidia_hpet_detected = 1;
        return 0;
@@ -53,7 +53,7 @@ static void nvidia_bugs(void)
                return;
 
        nvidia_hpet_detected = 0;
-       acpi_table_parse(ACPI_HPET, nvidia_hpet_check);
+       acpi_table_parse(ACPI_SIG_HPET, nvidia_hpet_check);
        if (nvidia_hpet_detected == 0) {
                acpi_skip_timer_override = 1;
                printk(KERN_INFO "Nvidia board "
index b007433..0b3603a 100644 (file)
@@ -58,8 +58,8 @@ void __init clustered_apic_check(void)
         * Some x86_64 machines use physical APIC mode regardless of how many
         * procs/clusters are present (x86_64 ES7000 is an example).
         */
-       if (acpi_fadt.revision > FADT2_REVISION_ID)
-               if (acpi_fadt.force_apic_physical_destination_mode) {
+       if (acpi_gbl_FADT.header.revision > FADT2_REVISION_ID)
+               if (acpi_gbl_FADT.flags & ACPI_FADT_APIC_PHYSICAL) {
                        genapic = &apic_cluster;
                        goto print;
                }
index d7bad90..6be6730 100644 (file)
@@ -1956,24 +1956,31 @@ static struct irq_chip msi_chip = {
        .retrigger      = ioapic_retrigger_irq,
 };
 
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev)
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
 {
        struct msi_msg msg;
-       int ret;
+       int irq, ret;
+       irq = create_irq();
+       if (irq < 0)
+               return irq;
+
+       set_irq_msi(irq, desc);
        ret = msi_compose_msg(dev, irq, &msg);
-       if (ret < 0)
+       if (ret < 0) {
+               destroy_irq(irq);
                return ret;
+       }
 
        write_msi_msg(irq, &msg);
 
        set_irq_chip_and_handler_name(irq, &msi_chip, handle_edge_irq, "edge");
 
-       return 0;
+       return irq;
 }
 
 void arch_teardown_msi_irq(unsigned int irq)
 {
-       return;
+       destroy_irq(irq);
 }
 
 #endif /* CONFIG_PCI_MSI */
index 0807256..50dd8be 100644 (file)
@@ -798,7 +798,7 @@ int mp_register_gsi(u32 gsi, int triggering, int polarity)
                return gsi;
 
        /* Don't set up the ACPI SCI because it's already set up */
-       if (acpi_fadt.sci_int == gsi)
+       if (acpi_gbl_FADT.sci_interrupt == gsi)
                return gsi;
 
        ioapic = mp_find_ioapic(gsi);
index 697f0aa..eb18be5 100644 (file)
@@ -29,7 +29,7 @@ struct dma_mapping_ops swiotlb_dma_ops = {
        .dma_supported = NULL,
 };
 
-void pci_swiotlb_init(void)
+void __init pci_swiotlb_init(void)
 {
        /* don't initialize swiotlb if iommu=off (no_iommu=1) */
        if (!iommu_detected && !no_iommu && end_pfn > MAX_DMA32_PFN)
index 5cc76d0..335cc91 100644 (file)
@@ -498,7 +498,7 @@ static unsigned long get_cmos_time(void)
 {
        unsigned int year, mon, day, hour, min, sec;
        unsigned long flags;
-       unsigned extyear = 0;
+       unsigned century = 0;
 
        spin_lock_irqsave(&rtc_lock, flags);
 
@@ -510,9 +510,9 @@ static unsigned long get_cmos_time(void)
                mon = CMOS_READ(RTC_MONTH);
                year = CMOS_READ(RTC_YEAR);
 #ifdef CONFIG_ACPI
-               if (acpi_fadt.revision >= FADT2_REVISION_ID &&
-                                       acpi_fadt.century)
-                       extyear = CMOS_READ(acpi_fadt.century);
+               if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
+                                       acpi_gbl_FADT.century)
+                       century = CMOS_READ(acpi_gbl_FADT.century);
 #endif
        } while (sec != CMOS_READ(RTC_SECONDS));
 
@@ -530,10 +530,10 @@ static unsigned long get_cmos_time(void)
        BCD_TO_BIN(mon);
        BCD_TO_BIN(year);
 
-       if (extyear) {
-               BCD_TO_BIN(extyear);
-               year += extyear;
-               printk(KERN_INFO "Extended CMOS year: %d\n", extyear);
+       if (century) {
+               BCD_TO_BIN(century);
+               year += century * 100;
+               printk(KERN_INFO "Extended CMOS year: %d\n", century * 100);
        } else { 
                /*
                 * x86-64 systems only exists since 2002.
@@ -954,7 +954,7 @@ __cpuinit int unsynchronized_tsc(void)
        if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) {
 #ifdef CONFIG_ACPI
                /* But TSC doesn't tick in C3 so don't use it there */
-               if (acpi_fadt.length > 0 && acpi_fadt.plvl3_lat < 1000)
+               if (acpi_gbl_FADT.header.length > 0 && acpi_gbl_FADT.C3latency < 1000)
                        return 1;
 #endif
                return 0;
index 1087e15..2efe215 100644 (file)
@@ -101,7 +101,7 @@ static __init inline int srat_disabled(void)
 static __init int slit_valid(struct acpi_table_slit *slit)
 {
        int i, j;
-       int d = slit->localities;
+       int d = slit->locality_count;
        for (i = 0; i < d; i++) {
                for (j = 0; j < d; j++)  {
                        u8 val = slit->entry[d*i + j];
@@ -127,18 +127,18 @@ void __init acpi_numa_slit_init(struct acpi_table_slit *slit)
 
 /* Callback for Proximity Domain -> LAPIC mapping */
 void __init
-acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa)
+acpi_numa_processor_affinity_init(struct acpi_srat_cpu_affinity *pa)
 {
        int pxm, node;
        if (srat_disabled())
                return;
-       if (pa->header.length != sizeof(struct acpi_table_processor_affinity)) {
+       if (pa->header.length != sizeof(struct acpi_srat_cpu_affinity)) {
                bad_srat();
                return;
        }
-       if (pa->flags.enabled == 0)
+       if ((pa->flags & ACPI_SRAT_CPU_ENABLED) == 0)
                return;
-       pxm = pa->proximity_domain;
+       pxm = pa->proximity_domain_lo;
        node = setup_node(pxm);
        if (node < 0) {
                printk(KERN_ERR "SRAT: Too many proximity domains %x\n", pxm);
@@ -254,21 +254,21 @@ static int reserve_hotadd(int node, unsigned long start, unsigned long end)
        /* Looks good */
 
        if (nd->start == nd->end) {
-               nd->start = start;
-               nd->end = end;
+               nd->start = start;
+               nd->end = end;
                changed = 1;
-       } else {
-               if (nd->start == end) {
-                       nd->start = start;
+       } else {
+               if (nd->start == end) {
+                       nd->start = start;
                        changed = 1;
                }
-               if (nd->end == start) {
-                       nd->end = end;
+               if (nd->end == start) {
+                       nd->end = end;
                        changed = 1;
                }
                if (!changed)
                        printk(KERN_ERR "SRAT: Hotplug zone not continuous. Partly ignored\n");
-       }
+       }
 
        ret = update_end_of_memory(nd->end);
 
@@ -279,7 +279,7 @@ static int reserve_hotadd(int node, unsigned long start, unsigned long end)
 
 /* Callback for parsing of the Proximity Domain <-> Memory Area mappings */
 void __init
-acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
+acpi_numa_memory_affinity_init(struct acpi_srat_mem_affinity *ma)
 {
        struct bootnode *nd, oldnode;
        unsigned long start, end;
@@ -288,16 +288,17 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
 
        if (srat_disabled())
                return;
-       if (ma->header.length != sizeof(struct acpi_table_memory_affinity)) {
+       if (ma->header.length != sizeof(struct acpi_srat_mem_affinity)) {
                bad_srat();
                return;
        }
-       if (ma->flags.enabled == 0)
+       if ((ma->flags & ACPI_SRAT_MEM_ENABLED) == 0)
                return;
-       if (ma->flags.hot_pluggable && !save_add_info())
+
+       if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && !save_add_info())
                return;
-       start = ma->base_addr_lo | ((u64)ma->base_addr_hi << 32);
-       end = start + (ma->length_lo | ((u64)ma->length_hi << 32));
+       start = ma->base_address;
+       end = start + ma->length;
        pxm = ma->proximity_domain;
        node = setup_node(pxm);
        if (node < 0) {
@@ -337,7 +338,8 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
        push_node_boundaries(node, nd->start >> PAGE_SHIFT,
                                                nd->end >> PAGE_SHIFT);
 
-       if (ma->flags.hot_pluggable && (reserve_hotadd(node, start, end) < 0)) {
+       if ((ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) &&
+           (reserve_hotadd(node, start, end) < 0)) {
                /* Ignore hotadd region. Undo damage */
                printk(KERN_NOTICE "SRAT: Hotplug region ignored\n");
                *nd = oldnode;
@@ -394,7 +396,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
 
        /* First clean up the node list */
        for (i = 0; i < MAX_NUMNODES; i++) {
-               cutoff_node(i, start, end);
+               cutoff_node(i, start, end);
                if ((nodes[i].end - nodes[i].start) < NODE_MIN_SIZE) {
                        unparse_node(i);
                        node_set_offline(i);
@@ -426,7 +428,7 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
                if (!node_online(i))
                        setup_node_bootmem(i, nodes[i].start, nodes[i].end);
 
-       for (i = 0; i < NR_CPUS; i++) { 
+       for (i = 0; i < NR_CPUS; i++) {
                if (cpu_to_node[i] == NUMA_NO_NODE)
                        continue;
                if (!node_isset(cpu_to_node[i], nodes_parsed))
@@ -461,7 +463,7 @@ int __node_distance(int a, int b)
 
        if (!acpi_slit)
                return a == b ? 10 : 20;
-       index = acpi_slit->localities * node_to_pxm(a);
+       index = acpi_slit->locality_count * node_to_pxm(a);
        return acpi_slit->entry[index + node_to_pxm(b)];
 }
 
index f8b6b28..faabb6e 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
- * 
+ *
  * This is an 64bit optimized version that always keeps the full mmconfig
  * space mapped. This allows lockless config space operation.
  */
@@ -25,7 +25,7 @@ static DECLARE_BITMAP(fallback_slots, 32*MAX_CHECK_BUS);
 
 /* Static virtual mapping of the MMCONFIG aperture */
 struct mmcfg_virt {
-       struct acpi_table_mcfg_config *cfg;
+       struct acpi_mcfg_allocation *cfg;
        char __iomem *virt;
 };
 static struct mmcfg_virt *pci_mmcfg_virt;
@@ -33,14 +33,14 @@ static struct mmcfg_virt *pci_mmcfg_virt;
 static char __iomem *get_virt(unsigned int seg, unsigned bus)
 {
        int cfg_num = -1;
-       struct acpi_table_mcfg_config *cfg;
+       struct acpi_mcfg_allocation *cfg;
 
        while (1) {
                ++cfg_num;
                if (cfg_num >= pci_mmcfg_config_num)
                        break;
                cfg = pci_mmcfg_virt[cfg_num].cfg;
-               if (cfg->pci_segment_group_number != seg)
+               if (cfg->pci_segment != seg)
                        continue;
                if ((cfg->start_bus_number <= bus) &&
                    (cfg->end_bus_number >= bus))
@@ -52,7 +52,7 @@ static char __iomem *get_virt(unsigned int seg, unsigned bus)
           this applies to all busses. */
        cfg = &pci_mmcfg_config[0];
        if (pci_mmcfg_config_num == 1 &&
-               cfg->pci_segment_group_number == 0 &&
+               cfg->pci_segment == 0 &&
                (cfg->start_bus_number | cfg->end_bus_number) == 0)
                return pci_mmcfg_virt[0].virt;
 
@@ -170,19 +170,19 @@ void __init pci_mmcfg_init(int type)
        if ((pci_probe & PCI_PROBE_MMCONF) == 0)
                return;
 
-       acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+       acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
        if ((pci_mmcfg_config_num == 0) ||
            (pci_mmcfg_config == NULL) ||
-           (pci_mmcfg_config[0].base_address == 0))
+           (pci_mmcfg_config[0].address == 0))
                return;
 
        /* Only do this check when type 1 works. If it doesn't work
            assume we run on a Mac and always use MCFG */
-       if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].base_address,
-                       pci_mmcfg_config[0].base_address + MMCONFIG_APER_MIN,
+       if (type == 1 && !e820_all_mapped(pci_mmcfg_config[0].address,
+                       pci_mmcfg_config[0].address + MMCONFIG_APER_MIN,
                        E820_RESERVED)) {
-               printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %x is not E820-reserved\n",
-                               pci_mmcfg_config[0].base_address);
+               printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %lx is not E820-reserved\n",
+                               (unsigned long)pci_mmcfg_config[0].address);
                printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
                return;
        }
@@ -194,15 +194,16 @@ void __init pci_mmcfg_init(int type)
        }
        for (i = 0; i < pci_mmcfg_config_num; ++i) {
                pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
-               pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address,
+               pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].address,
                                                         MMCONFIG_APER_MAX);
                if (!pci_mmcfg_virt[i].virt) {
                        printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
                                        "segment %d\n",
-                              pci_mmcfg_config[i].pci_segment_group_number);
+                               pci_mmcfg_config[i].pci_segment);
                        return;
                }
-               printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
+               printk(KERN_INFO "PCI: Using MMCONFIG at %lx\n",
+                       (unsigned long)pci_mmcfg_config[i].address);
        }
 
        unreachable_devices();
index 92ba249..918b4d8 100644 (file)
@@ -74,14 +74,6 @@ config CRYPTO_SHA1
        help
          SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
 
-config CRYPTO_SHA1_S390
-       tristate "SHA1 digest algorithm (s390)"
-       depends on S390
-       select CRYPTO_ALGAPI
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
-
 config CRYPTO_SHA256
        tristate "SHA256 digest algorithm"
        select CRYPTO_ALGAPI
@@ -91,17 +83,6 @@ config CRYPTO_SHA256
          This version of SHA implements a 256 bit hash with 128 bits of
          security against collision attacks.
 
-config CRYPTO_SHA256_S390
-       tristate "SHA256 digest algorithm (s390)"
-       depends on S390
-       select CRYPTO_ALGAPI
-       help
-         This is the s390 hardware accelerated implementation of the
-         SHA256 secure hash standard (DFIPS 180-2).
-
-         This version of SHA implements a 256 bit hash with 128 bits of
-         security against collision attacks.
-
 config CRYPTO_SHA512
        tristate "SHA384 and SHA512 digest algorithms"
        select CRYPTO_ALGAPI
@@ -187,14 +168,6 @@ config CRYPTO_DES
        help
          DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
 
-config CRYPTO_DES_S390
-       tristate "DES and Triple DES cipher algorithms (s390)"
-       depends on S390
-       select CRYPTO_ALGAPI
-       select CRYPTO_BLKCIPHER
-       help
-         DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
-
 config CRYPTO_BLOWFISH
        tristate "Blowfish cipher algorithm"
        select CRYPTO_ALGAPI
@@ -336,28 +309,6 @@ config CRYPTO_AES_X86_64
 
          See <http://csrc.nist.gov/encryption/aes/> for more information.
 
-config CRYPTO_AES_S390
-       tristate "AES cipher algorithms (s390)"
-       depends on S390
-       select CRYPTO_ALGAPI
-       select CRYPTO_BLKCIPHER
-       help
-         This is the s390 hardware accelerated implementation of the
-         AES cipher algorithms (FIPS-197). AES uses the Rijndael
-         algorithm.
-
-         Rijndael appears to be consistently a very good performer in
-         both hardware and software across a wide range of computing
-         environments regardless of its use in feedback or non-feedback
-         modes. Its key setup time is excellent, and its key agility is
-         good. Rijndael's very low memory requirements make it very well
-         suited for restricted-space environments, in which it also
-         demonstrates excellent performance. Rijndael's operations are
-         among the easiest to defend against power and timing attacks.
-
-         On s390 the System z9-109 currently only supports the key size
-         of 128 bit.
-
 config CRYPTO_CAST5
        tristate "CAST5 (CAST-128) cipher algorithm"
        select CRYPTO_ALGAPI
index f4f000a..20eacc2 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 menu "ACPI (Advanced Configuration and Power Interface) Support"
+       depends on !X86_NUMAQ
        depends on !X86_VISWS
        depends on !IA64_HP_SIM
        depends on IA64 || X86
@@ -77,6 +78,20 @@ config ACPI_SLEEP_PROC_SLEEP
          Create /proc/acpi/sleep
          Deprecated by /sys/power/state
 
+config ACPI_PROCFS
+       bool "Procfs interface (deprecated)"
+       depends on ACPI
+       default y
+       ---help---
+         Procfs interface for ACPI is made optional for back-compatible.
+         As the same functions are duplicated in sysfs interface
+         and this proc interface will be removed some time later,
+         it's marked as deprecated.
+         ( /proc/acpi/debug_layer && debug_level are deprecated by
+           /sys/module/acpi/parameters/debug_layer && debug_level.
+           /proc/acpi/info is deprecated by
+           /sys/module/acpi/parameters/acpica_version )
+
 config ACPI_AC
        tristate "AC Adapter"
        depends on X86
@@ -107,7 +122,7 @@ config ACPI_BUTTON
 
 config ACPI_VIDEO
        tristate "Video"
-       depends on X86
+       depends on X86 && BACKLIGHT_CLASS_DEVICE
        help
          This driver implement the ACPI Extensions For Display Adapters
          for integrated graphics devices on motherboard, as specified in
@@ -139,6 +154,13 @@ config ACPI_DOCK
        help
          This driver adds support for ACPI controlled docking stations
 
+config ACPI_BAY
+       tristate "Removable Drive Bay (EXPERIMENTAL)"
+       depends on EXPERIMENTAL
+       help
+         This driver adds support for ACPI controlled removable drive
+         bays such as the IBM ultrabay or the Dell Module Bay.
+
 config ACPI_PROCESSOR
        tristate "Processor"
        default y
@@ -186,19 +208,22 @@ config ACPI_ASUS
 
          Note: display switching code is currently considered EXPERIMENTAL,
          toying with these values may even lock your machine.
-          
+
           All settings are changed via /proc/acpi/asus directory entries. Owner
           and group for these entries can be set with asus_uid and asus_gid
           parameters.
-          
+
           More information and a userspace daemon for handling the extra buttons
           at <http://sourceforge.net/projects/acpi4asus/>.
-          
+
           If you have an ACPI-compatible ASUS laptop, say Y or M here. This
           driver is still under development, so if your laptop is unsupported or
           something works not quite as expected, please use the mailing list
-          available on the above page (acpi4asus-user@lists.sourceforge.net)
-          
+          available on the above page (acpi4asus-user@lists.sourceforge.net).
+
+         NOTE: This driver is deprecated and will probably be removed soon,
+         use asus-laptop instead.
+
 config ACPI_IBM
        tristate "IBM ThinkPad Laptop Extras"
        depends on X86
index bce7ca2..856c32b 100644 (file)
@@ -37,13 +37,15 @@ endif
 
 obj-y                          += sleep/
 obj-y                          += bus.o glue.o
+obj-y                          += scan.o
 obj-$(CONFIG_ACPI_AC)          += ac.o
 obj-$(CONFIG_ACPI_BATTERY)     += battery.o
 obj-$(CONFIG_ACPI_BUTTON)      += button.o
 obj-$(CONFIG_ACPI_EC)          += ec.o
 obj-$(CONFIG_ACPI_FAN)         += fan.o
 obj-$(CONFIG_ACPI_DOCK)                += dock.o
-obj-$(CONFIG_ACPI_VIDEO)       += video.o 
+obj-$(CONFIG_ACPI_BAY)         += bay.o
+obj-$(CONFIG_ACPI_VIDEO)       += video.o
 obj-$(CONFIG_ACPI_HOTKEY)      += hotkey.o
 obj-y                          += pci_root.o pci_link.o pci_irq.o pci_bind.o
 obj-$(CONFIG_ACPI_POWER)       += power.o
@@ -56,7 +58,6 @@ obj-$(CONFIG_ACPI_NUMA)               += numa.o
 obj-$(CONFIG_ACPI_ASUS)                += asus_acpi.o
 obj-$(CONFIG_ACPI_IBM)         += ibm_acpi.o
 obj-$(CONFIG_ACPI_TOSHIBA)     += toshiba_acpi.o
-obj-y                          += scan.o motherboard.o
 obj-$(CONFIG_ACPI_HOTPLUG_MEMORY)      += acpi_memhotplug.o
 obj-y                          += cm_sbs.o
 obj-$(CONFIG_ACPI_SBS)         += i2c_ec.o sbs.o
index 396140b..31ad70a 100644 (file)
@@ -26,7 +26,7 @@
  *  Pontus Fuchs   - Helper functions, cleanup
  *  Johann Wiesner - Small compile fixes
  *  John Belmonte  - ACPI code for Toshiba laptop was a good starting point.
- *  Ã‰ric Burghard  - LED display support for W1N
+ *  ï¿½ic Burghard  - LED display support for W1N
  *
  */
 
@@ -1128,7 +1128,6 @@ static int asus_model_match(char *model)
 static int asus_hotk_get_info(void)
 {
        struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
        union acpi_object *model = NULL;
        int bsts_result;
        char *string = NULL;
@@ -1142,11 +1141,9 @@ static int asus_hotk_get_info(void)
         * HID), this bit will be moved. A global variable asus_info contains
         * the DSDT header.
         */
-       status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt);
+       status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
        if (ACPI_FAILURE(status))
                printk(KERN_WARNING "  Couldn't get the DSDT table header\n");
-       else
-               asus_info = dsdt.pointer;
 
        /* We have to write 0 on init this far for all ASUS models */
        if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
@@ -1358,8 +1355,6 @@ static void __exit asus_acpi_exit(void)
        acpi_bus_unregister_driver(&asus_hotk_driver);
        remove_proc_entry(PROC_ASUS, acpi_root_dir);
 
-       kfree(asus_info);
-
        return;
 }
 
index 5f43e0d..2f4521a 100644 (file)
@@ -64,7 +64,7 @@ extern void *acpi_unlock_battery_dir(struct proc_dir_entry *acpi_battery_dir);
 
 static int acpi_battery_add(struct acpi_device *device);
 static int acpi_battery_remove(struct acpi_device *device, int type);
-static int acpi_battery_resume(struct acpi_device *device, int status);
+static int acpi_battery_resume(struct acpi_device *device);
 
 static struct acpi_driver acpi_battery_driver = {
        .name = ACPI_BATTERY_DRIVER_NAME,
@@ -753,7 +753,7 @@ static int acpi_battery_remove(struct acpi_device *device, int type)
 }
 
 /* this is needed to learn about changes made in suspended state */
-static int acpi_battery_resume(struct acpi_device *device, int state)
+static int acpi_battery_resume(struct acpi_device *device)
 {
        struct acpi_battery *battery;
 
diff --git a/drivers/acpi/bay.c b/drivers/acpi/bay.c
new file mode 100644 (file)
index 0000000..667fa1d
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+ *  bay.c - ACPI removable drive bay driver
+ *
+ *  Copyright (C) 2006 Kristen Carlson Accardi <kristen.c.accardi@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or (at
+ *  your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/notifier.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+#include <linux/platform_device.h>
+
+#define ACPI_BAY_DRIVER_NAME "ACPI Removable Drive Bay Driver"
+
+ACPI_MODULE_NAME("bay")
+MODULE_AUTHOR("Kristen Carlson Accardi");
+MODULE_DESCRIPTION(ACPI_BAY_DRIVER_NAME);
+MODULE_LICENSE("GPL");
+#define ACPI_BAY_CLASS "bay"
+#define ACPI_BAY_COMPONENT     0x10000000
+#define _COMPONENT ACPI_BAY_COMPONENT
+#define bay_dprintk(h,s) {\
+       char prefix[80] = {'\0'};\
+       struct acpi_buffer buffer = {sizeof(prefix), prefix};\
+       acpi_get_name(h, ACPI_FULL_PATHNAME, &buffer);\
+       printk(KERN_DEBUG PREFIX "%s: %s\n", prefix, s); }
+static void bay_notify(acpi_handle handle, u32 event, void *data);
+static int acpi_bay_add(struct acpi_device *device);
+static int acpi_bay_remove(struct acpi_device *device, int type);
+
+static struct acpi_driver acpi_bay_driver = {
+       .name = ACPI_BAY_DRIVER_NAME,
+       .class = ACPI_BAY_CLASS,
+       .ids = ACPI_BAY_HID,
+       .ops = {
+               .add = acpi_bay_add,
+               .remove = acpi_bay_remove,
+               },
+};
+
+struct bay {
+       acpi_handle handle;
+       char *name;
+       struct list_head list;
+       struct platform_device *pdev;
+};
+
+static LIST_HEAD(drive_bays);
+
+
+/*****************************************************************************
+ *                         Drive Bay functions                               *
+ *****************************************************************************/
+/**
+ * is_ejectable - see if a device is ejectable
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object has a _EJ0 method, then it is ejectable
+ */
+static int is_ejectable(acpi_handle handle)
+{
+       acpi_status status;
+       acpi_handle tmp;
+
+       status = acpi_get_handle(handle, "_EJ0", &tmp);
+       if (ACPI_FAILURE(status))
+               return 0;
+       return 1;
+}
+
+/**
+ * bay_present - see if the bay device is present
+ * @bay: the drive bay
+ *
+ * execute the _STA method.
+ */
+static int bay_present(struct bay *bay)
+{
+       unsigned long sta;
+       acpi_status status;
+
+       if (bay) {
+               status = acpi_evaluate_integer(bay->handle, "_STA", NULL, &sta);
+               if (ACPI_SUCCESS(status) && sta)
+                       return 1;
+       }
+       return 0;
+}
+
+/**
+ * eject_device - respond to an eject request
+ * @handle - the device to eject
+ *
+ * Call this devices _EJ0 method.
+ */
+static void eject_device(acpi_handle handle)
+{
+       struct acpi_object_list arg_list;
+       union acpi_object arg;
+
+       bay_dprintk(handle, "Ejecting device");
+
+       arg_list.count = 1;
+       arg_list.pointer = &arg;
+       arg.type = ACPI_TYPE_INTEGER;
+       arg.integer.value = 1;
+
+       if (ACPI_FAILURE(acpi_evaluate_object(handle, "_EJ0",
+                                             &arg_list, NULL)))
+               pr_debug("Failed to evaluate _EJ0!\n");
+}
+
+/*
+ * show_present - read method for "present" file in sysfs
+ */
+static ssize_t show_present(struct device *dev,
+                          struct device_attribute *attr, char *buf)
+{
+       struct bay *bay = dev_get_drvdata(dev);
+       return snprintf(buf, PAGE_SIZE, "%d\n", bay_present(bay));
+
+}
+DEVICE_ATTR(present, S_IRUGO, show_present, NULL);
+
+/*
+ * write_eject - write method for "eject" file in sysfs
+ */
+static ssize_t write_eject(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       struct bay *bay = dev_get_drvdata(dev);
+
+       if (!count)
+               return -EINVAL;
+
+       eject_device(bay->handle);
+       return count;
+}
+DEVICE_ATTR(eject, S_IWUSR, NULL, write_eject);
+
+/**
+ * is_ata - see if a device is an ata device
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object has one of 4 ATA ACPI methods defined,
+ * then it is an ATA device
+ */
+static int is_ata(acpi_handle handle)
+{
+       acpi_handle tmp;
+
+       if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
+          (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
+          (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
+          (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
+               return 1;
+
+       return 0;
+}
+
+/**
+ * parent_is_ata(acpi_handle handle)
+ *
+ */
+static int parent_is_ata(acpi_handle handle)
+{
+       acpi_handle phandle;
+
+       if (acpi_get_parent(handle, &phandle))
+               return 0;
+
+       return is_ata(phandle);
+}
+
+/**
+ * is_ejectable_bay - see if a device is an ejectable drive bay
+ * @handle: acpi handle of the device
+ *
+ * If an acpi object is ejectable and has one of the ACPI ATA
+ * methods defined, then we can safely call it an ejectable
+ * drive bay
+ */
+static int is_ejectable_bay(acpi_handle handle)
+{
+       if ((is_ata(handle) || parent_is_ata(handle)) && is_ejectable(handle))
+               return 1;
+       return 0;
+}
+
+/**
+ * eject_removable_drive - try to eject this drive
+ * @dev : the device structure of the drive
+ *
+ * If a device is a removable drive that requires an _EJ0 method
+ * to be executed in order to safely remove from the system, do
+ * it.  ATM - always returns success
+ */
+int eject_removable_drive(struct device *dev)
+{
+       acpi_handle handle = DEVICE_ACPI_HANDLE(dev);
+
+       if (handle) {
+               bay_dprintk(handle, "Got device handle");
+               if (is_ejectable_bay(handle))
+                       eject_device(handle);
+       } else {
+               printk("No acpi handle for device\n");
+       }
+
+       /* should I return an error code? */
+       return 0;
+}
+EXPORT_SYMBOL_GPL(eject_removable_drive);
+
+static int acpi_bay_add(struct acpi_device *device)
+{
+       bay_dprintk(device->handle, "adding bay device");
+       strcpy(acpi_device_name(device), "Dockable Bay");
+       strcpy(acpi_device_class(device), "bay");
+       return 0;
+}
+
+static int acpi_bay_add_fs(struct bay *bay)
+{
+       int ret;
+       struct device *dev = &bay->pdev->dev;
+
+       ret = device_create_file(dev, &dev_attr_present);
+       if (ret)
+               goto add_fs_err;
+       ret = device_create_file(dev, &dev_attr_eject);
+       if (ret) {
+               device_remove_file(dev, &dev_attr_present);
+               goto add_fs_err;
+       }
+       return 0;
+
+ add_fs_err:
+       bay_dprintk(bay->handle, "Error adding sysfs files\n");
+       return ret;
+}
+
+static void acpi_bay_remove_fs(struct bay *bay)
+{
+       struct device *dev = &bay->pdev->dev;
+
+       /* cleanup sysfs */
+       device_remove_file(dev, &dev_attr_present);
+       device_remove_file(dev, &dev_attr_eject);
+}
+
+static int bay_is_dock_device(acpi_handle handle)
+{
+       acpi_handle parent;
+
+       acpi_get_parent(handle, &parent);
+
+       /* if the device or it's parent is dependent on the
+        * dock, then we are a dock device
+        */
+       return (is_dock_device(handle) || is_dock_device(parent));
+}
+
+static int bay_add(acpi_handle handle, int id)
+{
+       acpi_status status;
+       struct bay *new_bay;
+       struct platform_device *pdev;
+       struct acpi_buffer nbuffer = {ACPI_ALLOCATE_BUFFER, NULL};
+       acpi_get_name(handle, ACPI_FULL_PATHNAME, &nbuffer);
+
+       bay_dprintk(handle, "Adding notify handler");
+
+       /*
+        * Initialize bay device structure
+        */
+       new_bay = kzalloc(GFP_ATOMIC, sizeof(*new_bay));
+       INIT_LIST_HEAD(&new_bay->list);
+       new_bay->handle = handle;
+       new_bay->name = (char *)nbuffer.pointer;
+
+       /* initialize platform device stuff */
+       pdev = platform_device_register_simple(ACPI_BAY_CLASS, id, NULL, 0);
+       if (pdev == NULL) {
+               printk(KERN_ERR PREFIX "Error registering bay device\n");
+               goto bay_add_err;
+       }
+       new_bay->pdev = pdev;
+       platform_set_drvdata(pdev, new_bay);
+
+       if (acpi_bay_add_fs(new_bay)) {
+               platform_device_unregister(new_bay->pdev);
+               goto bay_add_err;
+       }
+
+       /* register for events on this device */
+       status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+                       bay_notify, new_bay);
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_ERR PREFIX "Error installing bay notify handler\n");
+       }
+
+       /* if we are on a dock station, we should register for dock
+        * notifications.
+        */
+       if (bay_is_dock_device(handle)) {
+               bay_dprintk(handle, "Is dependent on dock\n");
+               register_hotplug_dock_device(handle, bay_notify, new_bay);
+       }
+       list_add(&new_bay->list, &drive_bays);
+       printk(KERN_INFO PREFIX "Bay [%s] Added\n", new_bay->name);
+       return 0;
+
+bay_add_err:
+       kfree(new_bay->name);
+       kfree(new_bay);
+       return -ENODEV;
+}
+
+static int acpi_bay_remove(struct acpi_device *device, int type)
+{
+       /*** FIXME: do something here */
+       return 0;
+}
+
+/**
+ * bay_create_acpi_device - add new devices to acpi
+ * @handle - handle of the device to add
+ *
+ *  This function will create a new acpi_device for the given
+ *  handle if one does not exist already.  This should cause
+ *  acpi to scan for drivers for the given devices, and call
+ *  matching driver's add routine.
+ *
+ *  Returns a pointer to the acpi_device corresponding to the handle.
+ */
+static struct acpi_device * bay_create_acpi_device(acpi_handle handle)
+{
+       struct acpi_device *device = NULL;
+       struct acpi_device *parent_device;
+       acpi_handle parent;
+       int ret;
+
+       bay_dprintk(handle, "Trying to get device");
+       if (acpi_bus_get_device(handle, &device)) {
+               /*
+                * no device created for this object,
+                * so we should create one.
+                */
+               bay_dprintk(handle, "No device for handle");
+               acpi_get_parent(handle, &parent);
+               if (acpi_bus_get_device(parent, &parent_device))
+                       parent_device = NULL;
+
+               ret = acpi_bus_add(&device, parent_device, handle,
+                       ACPI_BUS_TYPE_DEVICE);
+               if (ret) {
+                       pr_debug("error adding bus, %x\n",
+                               -ret);
+                       return NULL;
+               }
+       }
+       return device;
+}
+
+/**
+ * bay_notify - act upon an acpi bay notification
+ * @handle: the bay handle
+ * @event: the acpi event
+ * @data: our driver data struct
+ *
+ */
+static void bay_notify(acpi_handle handle, u32 event, void *data)
+{
+       struct acpi_device *dev;
+
+       bay_dprintk(handle, "Bay event");
+
+       switch(event) {
+       case ACPI_NOTIFY_BUS_CHECK:
+               printk("Bus Check\n");
+       case ACPI_NOTIFY_DEVICE_CHECK:
+               printk("Device Check\n");
+               dev = bay_create_acpi_device(handle);
+               if (dev)
+                       acpi_bus_generate_event(dev, event, 0);
+               else
+                       printk("No device for generating event\n");
+               /* wouldn't it be a good idea to just rescan SATA
+                * right here?
+                */
+               break;
+       case ACPI_NOTIFY_EJECT_REQUEST:
+               printk("Eject request\n");
+               dev = bay_create_acpi_device(handle);
+               if (dev)
+                       acpi_bus_generate_event(dev, event, 0);
+               else
+                       printk("No device for generating eventn");
+
+               /* wouldn't it be a good idea to just call the
+                * eject_device here if we were a SATA device?
+                */
+               break;
+       default:
+               printk("unknown event %d\n", event);
+       }
+}
+
+static acpi_status
+find_bay(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+       int *count = (int *)context;
+
+       /*
+        * there could be more than one ejectable bay.
+        * so, just return AE_OK always so that every object
+        * will be checked.
+        */
+       if (is_ejectable_bay(handle)) {
+               bay_dprintk(handle, "found ejectable bay");
+               if (!bay_add(handle, *count))
+                       (*count)++;
+       }
+       return AE_OK;
+}
+
+static int __init bay_init(void)
+{
+       int bays = 0;
+
+       INIT_LIST_HEAD(&drive_bays);
+
+       /* look for dockable drive bays */
+       acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+               ACPI_UINT32_MAX, find_bay, &bays, NULL);
+
+       if (bays)
+               if ((acpi_bus_register_driver(&acpi_bay_driver) < 0))
+                       printk(KERN_ERR "Unable to register bay driver\n");
+
+       if (!bays)
+               return -ENODEV;
+
+       return 0;
+}
+
+static void __exit bay_exit(void)
+{
+       struct bay *bay, *tmp;
+
+       list_for_each_entry_safe(bay, tmp, &drive_bays, list) {
+               if (is_dock_device(bay->handle))
+                       unregister_hotplug_dock_device(bay->handle);
+               acpi_bay_remove_fs(bay);
+               acpi_remove_notify_handler(bay->handle, ACPI_SYSTEM_NOTIFY,
+                       bay_notify);
+               platform_device_unregister(bay->pdev);
+               kfree(bay->name);
+               kfree(bay);
+       }
+
+       acpi_bus_unregister_driver(&acpi_bay_driver);
+}
+
+postcore_initcall(bay_init);
+module_exit(bay_exit);
+
index f9c972b..f289fd4 100644 (file)
@@ -44,7 +44,7 @@ struct acpi_blacklist_item {
        char oem_id[7];
        char oem_table_id[9];
        u32 oem_revision;
-       acpi_table_type table;
+       char *table;
        enum acpi_blacklist_predicates oem_revision_predicate;
        char *reason;
        u32 is_critical_error;
@@ -56,18 +56,18 @@ struct acpi_blacklist_item {
  */
 static struct acpi_blacklist_item acpi_blacklist[] __initdata = {
        /* Compaq Presario 1700 */
-       {"PTLTD ", "  DSDT  ", 0x06040000, ACPI_DSDT, less_than_or_equal,
+       {"PTLTD ", "  DSDT  ", 0x06040000, ACPI_SIG_DSDT, less_than_or_equal,
         "Multiple problems", 1},
        /* Sony FX120, FX140, FX150? */
-       {"SONY  ", "U0      ", 0x20010313, ACPI_DSDT, less_than_or_equal,
+       {"SONY  ", "U0      ", 0x20010313, ACPI_SIG_DSDT, less_than_or_equal,
         "ACPI driver problem", 1},
        /* Compaq Presario 800, Insyde BIOS */
-       {"INT440", "SYSFexxx", 0x00001001, ACPI_DSDT, less_than_or_equal,
+       {"INT440", "SYSFexxx", 0x00001001, ACPI_SIG_DSDT, less_than_or_equal,
         "Does not use _REG to protect EC OpRegions", 1},
        /* IBM 600E - _ADR should return 7, but it returns 1 */
-       {"IBM   ", "TP600E  ", 0x00000105, ACPI_DSDT, less_than_or_equal,
+       {"IBM   ", "TP600E  ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal,
         "Incorrect _ADR", 1},
-       {"ASUS\0\0", "P2B-S   ", 0, ACPI_DSDT, all_versions,
+       {"ASUS\0\0", "P2B-S   ", 0, ACPI_SIG_DSDT, all_versions,
         "Bogus PCI routing", 1},
 
        {""}
@@ -79,7 +79,7 @@ static int __init blacklist_by_year(void)
 {
        int year = dmi_get_year(DMI_BIOS_DATE);
        /* Doesn't exist? Likely an old system */
-       if (year == -1) 
+       if (year == -1)
                return 1;
        /* 0? Likely a buggy new BIOS */
        if (year == 0)
@@ -103,22 +103,21 @@ int __init acpi_blacklisted(void)
 {
        int i = 0;
        int blacklisted = 0;
-       struct acpi_table_header *table_header;
+       struct acpi_table_header table_header;
 
        while (acpi_blacklist[i].oem_id[0] != '\0') {
-               if (acpi_get_table_header_early
-                   (acpi_blacklist[i].table, &table_header)) {
+               if (acpi_get_table_header(acpi_blacklist[i].table, 0, &table_header)) {
                        i++;
                        continue;
                }
 
-               if (strncmp(acpi_blacklist[i].oem_id, table_header->oem_id, 6)) {
+               if (strncmp(acpi_blacklist[i].oem_id, table_header.oem_id, 6)) {
                        i++;
                        continue;
                }
 
                if (strncmp
-                   (acpi_blacklist[i].oem_table_id, table_header->oem_table_id,
+                   (acpi_blacklist[i].oem_table_id, table_header.oem_table_id,
                     8)) {
                        i++;
                        continue;
@@ -127,14 +126,14 @@ int __init acpi_blacklisted(void)
                if ((acpi_blacklist[i].oem_revision_predicate == all_versions)
                    || (acpi_blacklist[i].oem_revision_predicate ==
                        less_than_or_equal
-                       && table_header->oem_revision <=
+                       && table_header.oem_revision <=
                        acpi_blacklist[i].oem_revision)
                    || (acpi_blacklist[i].oem_revision_predicate ==
                        greater_than_or_equal
-                       && table_header->oem_revision >=
+                       && table_header.oem_revision >=
                        acpi_blacklist[i].oem_revision)
                    || (acpi_blacklist[i].oem_revision_predicate == equal
-                       && table_header->oem_revision ==
+                       && table_header.oem_revision ==
                        acpi_blacklist[i].oem_revision)) {
 
                        printk(KERN_ERR PREFIX
index 766332e..c26468d 100644 (file)
@@ -44,9 +44,6 @@ ACPI_MODULE_NAME("acpi_bus")
 extern void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger);
 #endif
 
-struct fadt_descriptor acpi_fadt;
-EXPORT_SYMBOL(acpi_fadt);
-
 struct acpi_device *acpi_root;
 struct proc_dir_entry *acpi_root_dir;
 EXPORT_SYMBOL(acpi_root_dir);
@@ -195,7 +192,7 @@ int acpi_bus_set_power(acpi_handle handle, int state)
 
        if (!device->flags.power_manageable) {
                ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device `[%s]' is not power manageable\n",
-                               device->kobj.name));
+                               device->dev.kobj.name));
                return -ENODEV;
        }
        /*
@@ -582,11 +579,12 @@ static int __init acpi_bus_init_irq(void)
        return 0;
 }
 
+acpi_native_uint acpi_gbl_permanent_mmap;
+
+
 void __init acpi_early_init(void)
 {
        acpi_status status = AE_OK;
-       struct acpi_buffer buffer = { sizeof(acpi_fadt), &acpi_fadt };
-
 
        if (acpi_disabled)
                return;
@@ -597,6 +595,15 @@ void __init acpi_early_init(void)
        if (!acpi_strict)
                acpi_gbl_enable_interpreter_slack = TRUE;
 
+       acpi_gbl_permanent_mmap = 1;
+
+       status = acpi_reallocate_root_table();
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_ERR PREFIX
+                      "Unable to reallocate ACPI tables\n");
+               goto error0;
+       }
+
        status = acpi_initialize_subsystem();
        if (ACPI_FAILURE(status)) {
                printk(KERN_ERR PREFIX
@@ -611,32 +618,25 @@ void __init acpi_early_init(void)
                goto error0;
        }
 
-       /*
-        * Get a separate copy of the FADT for use by other drivers.
-        */
-       status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &buffer);
-       if (ACPI_FAILURE(status)) {
-               printk(KERN_ERR PREFIX "Unable to get the FADT\n");
-               goto error0;
-       }
 #ifdef CONFIG_X86
        if (!acpi_ioapic) {
-               extern acpi_interrupt_flags acpi_sci_flags;
+               extern u8 acpi_sci_flags;
 
                /* compatible (0) means level (3) */
-               if (acpi_sci_flags.trigger == 0)
-                       acpi_sci_flags.trigger = 3;
-
+               if (!(acpi_sci_flags & ACPI_MADT_TRIGGER_MASK)) {
+                       acpi_sci_flags &= ~ACPI_MADT_TRIGGER_MASK;
+                       acpi_sci_flags |= ACPI_MADT_TRIGGER_LEVEL;
+               }
                /* Set PIC-mode SCI trigger type */
-               acpi_pic_sci_set_trigger(acpi_fadt.sci_int,
-                                        acpi_sci_flags.trigger);
+               acpi_pic_sci_set_trigger(acpi_gbl_FADT.sci_interrupt,
+                                        (acpi_sci_flags & ACPI_MADT_TRIGGER_MASK) >> 2);
        } else {
                extern int acpi_sci_override_gsi;
                /*
-                * now that acpi_fadt is initialized,
+                * now that acpi_gbl_FADT is initialized,
                 * update it with result from INT_SRC_OVR parsing
                 */
-               acpi_fadt.sci_int = acpi_sci_override_gsi;
+               acpi_gbl_FADT.sci_interrupt = acpi_sci_override_gsi;
        }
 #endif
 
index ac86058..c726612 100644 (file)
@@ -75,7 +75,7 @@ static int acpi_button_state_open_fs(struct inode *inode, struct file *file);
 static struct acpi_driver acpi_button_driver = {
        .name = ACPI_BUTTON_DRIVER_NAME,
        .class = ACPI_BUTTON_CLASS,
-       .ids = "ACPI_FPB,ACPI_FSB,PNP0C0D,PNP0C0C,PNP0C0E",
+       .ids = "button_power,button_sleep,PNP0C0D,PNP0C0C,PNP0C0E",
        .ops = {
                .add = acpi_button_add,
                .remove = acpi_button_remove,
index 0a1863e..69a68fd 100644 (file)
@@ -167,7 +167,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
                        if (ACPI_FAILURE(status) || !device) {
                                result = container_device_add(&device, handle);
                                if (!result)
-                                       kobject_uevent(&device->kobj,
+                                       kobject_uevent(&device->dev.kobj,
                                                       KOBJ_ONLINE);
                                else
                                        printk("Failed to add container\n");
@@ -175,13 +175,13 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
                } else {
                        if (ACPI_SUCCESS(status)) {
                                /* device exist and this is a remove request */
-                               kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+                               kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
                        }
                }
                break;
        case ACPI_NOTIFY_EJECT_REQUEST:
                if (!acpi_bus_get_device(handle, &device) && device) {
-                       kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+                       kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
                }
                break;
        default:
index 35c6af8..d48f65a 100644 (file)
 
 #define _COMPONENT             ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("debug")
-#define ACPI_SYSTEM_FILE_DEBUG_LAYER   "debug_layer"
-#define ACPI_SYSTEM_FILE_DEBUG_LEVEL   "debug_level"
+
 #ifdef MODULE_PARAM_PREFIX
 #undef MODULE_PARAM_PREFIX
 #endif
-#define MODULE_PARAM_PREFIX
-    module_param(acpi_dbg_layer, uint, 0400);
-module_param(acpi_dbg_level, uint, 0400);
+#define MODULE_PARAM_PREFIX "acpi."
 
 struct acpi_dlayer {
        const char *name;
@@ -86,6 +83,60 @@ static const struct acpi_dlevel acpi_debug_levels[] = {
        ACPI_DEBUG_INIT(ACPI_LV_EVENTS),
 };
 
+/* --------------------------------------------------------------------------
+                              FS Interface (/sys)
+   -------------------------------------------------------------------------- */
+static int param_get_debug_layer(char *buffer, struct kernel_param *kp) {
+       int result = 0;
+       int i;
+
+       result = sprintf(buffer, "%-25s\tHex        SET\n", "Description");
+
+       for(i = 0; i <ARRAY_SIZE(acpi_debug_layers); i++) {
+               result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n",
+                                       acpi_debug_layers[i].name,
+                                       acpi_debug_layers[i].value,
+                                       (acpi_dbg_layer & acpi_debug_layers[i].value) ? '*' : ' ');
+       }
+       result += sprintf(buffer+result, "%-25s\t0x%08X [%c]\n", "ACPI_ALL_DRIVERS",
+                                       ACPI_ALL_DRIVERS,
+                                       (acpi_dbg_layer & ACPI_ALL_DRIVERS) ==
+                                       ACPI_ALL_DRIVERS ? '*' : (acpi_dbg_layer &
+                                       ACPI_ALL_DRIVERS) == 0 ? ' ' : '-');
+       result += sprintf(buffer+result, "--\ndebug_layer = 0x%08X ( * = enabled)\n", acpi_dbg_layer);
+
+       return result;
+}
+
+static int param_get_debug_level(char *buffer, struct kernel_param *kp) {
+       int result = 0;
+       int i;
+
+       result = sprintf(buffer, "%-25s\tHex        SET\n", "Description");
+
+       for (i = 0; i < ARRAY_SIZE(acpi_debug_levels); i++) {
+               result += sprintf(buffer+result, "%-25s\t0x%08lX [%c]\n",
+                                    acpi_debug_levels[i].name,
+                                    acpi_debug_levels[i].value,
+                                    (acpi_dbg_level & acpi_debug_levels[i].
+                                     value) ? '*' : ' ');
+       }
+       result += sprintf(buffer+result, "--\ndebug_level = 0x%08X (* = enabled)\n",
+                            acpi_dbg_level);
+
+       return result;
+}
+
+module_param_call(debug_layer, param_set_uint, param_get_debug_layer, &acpi_dbg_layer, 0644);
+module_param_call(debug_level, param_set_uint, param_get_debug_level, &acpi_dbg_level, 0644);
+
+/* --------------------------------------------------------------------------
+                              FS Interface (/proc)
+   -------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
+#define ACPI_SYSTEM_FILE_DEBUG_LAYER   "debug_layer"
+#define ACPI_SYSTEM_FILE_DEBUG_LEVEL           "debug_level"
+
 static int
 acpi_system_read_debug(char *page,
                       char **start, off_t off, int count, int *eof, void *data)
@@ -221,3 +272,4 @@ static int __init acpi_debug_init(void)
 }
 
 subsys_initcall(acpi_debug_init);
+#endif
index a6d77ef..f049639 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -133,7 +133,8 @@ acpi_ds_create_buffer_field(union acpi_parse_object *op,
                }
        }
 
-       /* We could put the returned object (Node) on the object stack for later,
+       /*
+        * We could put the returned object (Node) on the object stack for later,
         * but for now, we will put it in the "op" object that the parser uses,
         * so we can get it again at the end of this scope
         */
@@ -514,8 +515,33 @@ acpi_ds_create_bank_field(union acpi_parse_object *op,
 
        /* Third arg is the bank_value */
 
+       /* TBD: This arg is a term_arg, not a constant, and must be evaluated */
+
        arg = arg->common.next;
-       info.bank_value = (u32) arg->common.value.integer;
+
+       /* Currently, only the following constants are supported */
+
+       switch (arg->common.aml_opcode) {
+       case AML_ZERO_OP:
+               info.bank_value = 0;
+               break;
+
+       case AML_ONE_OP:
+               info.bank_value = 1;
+               break;
+
+       case AML_BYTE_OP:
+       case AML_WORD_OP:
+       case AML_DWORD_OP:
+       case AML_QWORD_OP:
+               info.bank_value = (u32) arg->common.value.integer;
+               break;
+
+       default:
+               info.bank_value = 0;
+               ACPI_ERROR((AE_INFO,
+                           "Non-constant BankValue for BankField is not implemented"));
+       }
 
        /* Fourth arg is the field flags */
 
index 1888c05..af923c3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
 #include <acpi/acpi.h>
 #include <acpi/acdispat.h>
 #include <acpi/acnamesp.h>
+#include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_DISPATCHER
 ACPI_MODULE_NAME("dsinit")
@@ -90,7 +91,7 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
         * We are only interested in NS nodes owned by the table that
         * was just loaded
         */
-       if (node->owner_id != info->table_desc->owner_id) {
+       if (node->owner_id != info->owner_id) {
                return (AE_OK);
        }
 
@@ -150,14 +151,21 @@ acpi_ds_init_one_object(acpi_handle obj_handle,
  ******************************************************************************/
 
 acpi_status
-acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
+acpi_ds_initialize_objects(acpi_native_uint table_index,
                           struct acpi_namespace_node * start_node)
 {
        acpi_status status;
        struct acpi_init_walk_info info;
+       struct acpi_table_header *table;
+       acpi_owner_id owner_id;
 
        ACPI_FUNCTION_TRACE(ds_initialize_objects);
 
+       status = acpi_tb_get_owner_id(table_index, &owner_id);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
        ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
                          "**** Starting initialization of namespace objects ****\n"));
        ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT, "Parsing all Control Methods:"));
@@ -166,7 +174,8 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
        info.op_region_count = 0;
        info.object_count = 0;
        info.device_count = 0;
-       info.table_desc = table_desc;
+       info.table_index = table_index;
+       info.owner_id = owner_id;
 
        /* Walk entire namespace from the supplied root */
 
@@ -176,10 +185,14 @@ acpi_ds_initialize_objects(struct acpi_table_desc * table_desc,
                ACPI_EXCEPTION((AE_INFO, status, "During WalkNamespace"));
        }
 
+       status = acpi_get_table_by_index(table_index, &table);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
        ACPI_DEBUG_PRINT_RAW((ACPI_DB_INIT,
                              "\nTable [%4.4s](id %4.4X) - %hd Objects with %hd Devices %hd Methods %hd Regions\n",
-                             table_desc->pointer->signature,
-                             table_desc->owner_id, info.object_count,
+                             table->signature, owner_id, info.object_count,
                              info.device_count, info.method_count,
                              info.op_region_count));
 
index cf888ad..1cbe619 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -327,7 +327,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
        ACPI_FUNCTION_TRACE_PTR(ds_call_control_method, this_walk_state);
 
        ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-                         "Execute method %p, currentstate=%p\n",
+                         "Calling method %p, currentstate=%p\n",
                          this_walk_state->prev_op, this_walk_state));
 
        /*
@@ -351,49 +351,7 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
                return_ACPI_STATUS(status);
        }
 
-       /*
-        * 1) Parse the method. All "normal" methods are parsed for each execution.
-        * Internal methods (_OSI, etc.) do not require parsing.
-        */
-       if (!(obj_desc->method.method_flags & AML_METHOD_INTERNAL_ONLY)) {
-
-               /* Create a new walk state for the parse */
-
-               next_walk_state =
-                   acpi_ds_create_walk_state(obj_desc->method.owner_id, op,
-                                             obj_desc, NULL);
-               if (!next_walk_state) {
-                       status = AE_NO_MEMORY;
-                       goto cleanup;
-               }
-
-               /* Create and init a parse tree root */
-
-               op = acpi_ps_create_scope_op();
-               if (!op) {
-                       status = AE_NO_MEMORY;
-                       goto cleanup;
-               }
-
-               status = acpi_ds_init_aml_walk(next_walk_state, op, method_node,
-                                              obj_desc->method.aml_start,
-                                              obj_desc->method.aml_length,
-                                              NULL, 1);
-               if (ACPI_FAILURE(status)) {
-                       acpi_ps_delete_parse_tree(op);
-                       goto cleanup;
-               }
-
-               /* Begin AML parse (deletes next_walk_state) */
-
-               status = acpi_ps_parse_aml(next_walk_state);
-               acpi_ps_delete_parse_tree(op);
-               if (ACPI_FAILURE(status)) {
-                       goto cleanup;
-               }
-       }
-
-       /* 2) Begin method execution. Create a new walk state */
+       /* Begin method parse/execution. Create a new walk state */
 
        next_walk_state = acpi_ds_create_walk_state(obj_desc->method.owner_id,
                                                    NULL, obj_desc, thread);
@@ -424,7 +382,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
 
        status = acpi_ds_init_aml_walk(next_walk_state, NULL, method_node,
                                       obj_desc->method.aml_start,
-                                      obj_desc->method.aml_length, info, 3);
+                                      obj_desc->method.aml_length, info,
+                                      ACPI_IMODE_EXECUTE);
 
        ACPI_FREE(info);
        if (ACPI_FAILURE(status)) {
@@ -445,8 +404,8 @@ acpi_ds_call_control_method(struct acpi_thread_state *thread,
        this_walk_state->num_operands = 0;
 
        ACPI_DEBUG_PRINT((ACPI_DB_DISPATCH,
-                         "Starting nested execution, newstate=%p\n",
-                         next_walk_state));
+                         "**** Begin nested execution of [%4.4s] **** WalkState=%p\n",
+                         method_node->name.ascii, next_walk_state));
 
        /* Invoke an internal method if necessary */
 
index 459160f..ba4626e 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 72190ab..a474ca2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -260,7 +260,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
        }
 
        obj_desc->buffer.flags |= AOPOBJ_DATA_VALID;
-       op->common.node = (struct acpi_namespace_node *)obj_desc;
+       op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);
        return_ACPI_STATUS(AE_OK);
 }
 
@@ -270,7 +270,8 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
  *
  * PARAMETERS:  walk_state      - Current walk state
  *              Op              - Parser object to be translated
- *              package_length  - Number of elements in the package
+ *              element_count   - Number of elements in the package - this is
+ *                                the num_elements argument to Package()
  *              obj_desc_ptr    - Where the ACPI internal object is returned
  *
  * RETURN:      Status
@@ -278,18 +279,29 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state,
  * DESCRIPTION: Translate a parser Op package object to the equivalent
  *              namespace object
  *
+ * NOTE: The number of elements in the package will be always be the num_elements
+ * count, regardless of the number of elements in the package list. If
+ * num_elements is smaller, only that many package list elements are used.
+ * if num_elements is larger, the Package object is padded out with
+ * objects of type Uninitialized (as per ACPI spec.)
+ *
+ * Even though the ASL compilers do not allow num_elements to be smaller
+ * than the Package list length (for the fixed length package opcode), some
+ * BIOS code modifies the AML on the fly to adjust the num_elements, and
+ * this code compensates for that. This also provides compatibility with
+ * other AML interpreters.
+ *
  ******************************************************************************/
 
 acpi_status
 acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
                                   union acpi_parse_object *op,
-                                  u32 package_length,
+                                  u32 element_count,
                                   union acpi_operand_object **obj_desc_ptr)
 {
        union acpi_parse_object *arg;
        union acpi_parse_object *parent;
        union acpi_operand_object *obj_desc = NULL;
-       u32 package_list_length;
        acpi_status status = AE_OK;
        acpi_native_uint i;
 
@@ -318,32 +330,13 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
                obj_desc->package.node = parent->common.node;
        }
 
-       obj_desc->package.count = package_length;
-
-       /* Count the number of items in the package list */
-
-       arg = op->common.value.arg;
-       arg = arg->common.next;
-       for (package_list_length = 0; arg; package_list_length++) {
-               arg = arg->common.next;
-       }
-
-       /*
-        * The package length (number of elements) will be the greater
-        * of the specified length and the length of the initializer list
-        */
-       if (package_list_length > package_length) {
-               obj_desc->package.count = package_list_length;
-       }
-
        /*
-        * Allocate the pointer array (array of pointers to the
-        * individual objects). Add an extra pointer slot so
-        * that the list is always null terminated.
+        * Allocate the element array (array of pointers to the individual
+        * objects) based on the num_elements parameter. Add an extra pointer slot
+        * so that the list is always null terminated.
         */
        obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size)
-                                                          obj_desc->package.
-                                                          count +
+                                                          element_count +
                                                           1) * sizeof(void *));
 
        if (!obj_desc->package.elements) {
@@ -351,15 +344,20 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
                return_ACPI_STATUS(AE_NO_MEMORY);
        }
 
+       obj_desc->package.count = element_count;
+
        /*
-        * Initialize all elements of the package
+        * Initialize the elements of the package, up to the num_elements count.
+        * Package is automatically padded with uninitialized (NULL) elements
+        * if num_elements is greater than the package list length. Likewise,
+        * Package is truncated if num_elements is less than the list length.
         */
        arg = op->common.value.arg;
        arg = arg->common.next;
-       for (i = 0; arg; i++) {
+       for (i = 0; arg && (i < element_count); i++) {
                if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
 
-                       /* Object (package or buffer) is already built */
+                       /* This package element is already built, just get it */
 
                        obj_desc->package.elements[i] =
                            ACPI_CAST_PTR(union acpi_operand_object,
@@ -373,8 +371,14 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state,
                arg = arg->common.next;
        }
 
+       if (!arg) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                                 "Package List length larger than NumElements count (%X), truncated\n",
+                                 element_count));
+       }
+
        obj_desc->package.flags |= AOPOBJ_DATA_VALID;
-       op->common.node = (struct acpi_namespace_node *)obj_desc;
+       op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc);
        return_ACPI_STATUS(status);
 }
 
@@ -488,8 +492,9 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
                /*
                 * Defer evaluation of Buffer term_arg operand
                 */
-               obj_desc->buffer.node = (struct acpi_namespace_node *)
-                   walk_state->operands[0];
+               obj_desc->buffer.node =
+                   ACPI_CAST_PTR(struct acpi_namespace_node,
+                                 walk_state->operands[0]);
                obj_desc->buffer.aml_start = op->named.data;
                obj_desc->buffer.aml_length = op->named.length;
                break;
@@ -499,8 +504,9 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state,
                /*
                 * Defer evaluation of Package term_arg operand
                 */
-               obj_desc->package.node = (struct acpi_namespace_node *)
-                   walk_state->operands[0];
+               obj_desc->package.node =
+                   ACPI_CAST_PTR(struct acpi_namespace_node,
+                                 walk_state->operands[0]);
                obj_desc->package.aml_start = op->named.data;
                obj_desc->package.aml_length = op->named.length;
                break;
index 5b974a8..6c6104a 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -114,7 +114,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node,
        }
 
        status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
-                                      aml_length, NULL, 1);
+                                      aml_length, NULL, ACPI_IMODE_LOAD_PASS1);
        if (ACPI_FAILURE(status)) {
                acpi_ds_delete_walk_state(walk_state);
                goto cleanup;
@@ -157,7 +157,7 @@ acpi_ds_execute_arguments(struct acpi_namespace_node *node,
        /* Execute the opcode and arguments */
 
        status = acpi_ds_init_aml_walk(walk_state, op, NULL, aml_start,
-                                      aml_length, NULL, 3);
+                                      aml_length, NULL, ACPI_IMODE_EXECUTE);
        if (ACPI_FAILURE(status)) {
                acpi_ds_delete_walk_state(walk_state);
                goto cleanup;
index 05230ba..e4073e0 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d7a616c..69693fa 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -219,7 +219,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
        if (!op) {
                status = acpi_ds_load2_begin_op(walk_state, out_op);
                if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
+                       goto error_exit;
                }
 
                op = *out_op;
@@ -238,7 +238,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
 
                        status = acpi_ds_scope_stack_pop(walk_state);
                        if (ACPI_FAILURE(status)) {
-                               return_ACPI_STATUS(status);
+                               goto error_exit;
                        }
                }
        }
@@ -287,7 +287,7 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
 
                status = acpi_ds_result_stack_push(walk_state);
                if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
+                       goto error_exit;
                }
 
                status = acpi_ds_exec_begin_control_op(walk_state, op);
@@ -328,6 +328,10 @@ acpi_ds_exec_begin_op(struct acpi_walk_state *walk_state,
        /* Nothing to do here during method execution */
 
        return_ACPI_STATUS(status);
+
+      error_exit:
+       status = acpi_ds_method_error(status, walk_state);
+       return_ACPI_STATUS(status);
 }
 
 /*****************************************************************************
index e3ca7f6..8ab9d1b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -196,6 +196,7 @@ acpi_ds_load1_begin_op(struct acpi_walk_state * walk_state,
                 * one of the opcodes that actually opens a scope
                 */
                switch (node->type) {
+               case ACPI_TYPE_ANY:
                case ACPI_TYPE_LOCAL_SCOPE:     /* Scope  */
                case ACPI_TYPE_DEVICE:
                case ACPI_TYPE_POWER:
@@ -546,6 +547,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
        acpi_status status;
        acpi_object_type object_type;
        char *buffer_ptr;
+       u32 flags;
 
        ACPI_FUNCTION_TRACE(ds_load2_begin_op);
 
@@ -669,6 +671,7 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
                 * one of the opcodes that actually opens a scope
                 */
                switch (node->type) {
+               case ACPI_TYPE_ANY:
                case ACPI_TYPE_LOCAL_SCOPE:     /* Scope */
                case ACPI_TYPE_DEVICE:
                case ACPI_TYPE_POWER:
@@ -750,12 +753,20 @@ acpi_ds_load2_begin_op(struct acpi_walk_state *walk_state,
                        break;
                }
 
-               /* Add new entry into namespace */
+               flags = ACPI_NS_NO_UPSEARCH;
+               if (walk_state->pass_number == ACPI_IMODE_EXECUTE) {
+
+                       /* Execution mode, node cannot already exist, node is temporary */
+
+                       flags |= (ACPI_NS_ERROR_IF_FOUND | ACPI_NS_TEMPORARY);
+               }
+
+               /* Add new entry or lookup existing entry */
 
                status =
                    acpi_ns_lookup(walk_state->scope_info, buffer_ptr,
-                                  object_type, ACPI_IMODE_LOAD_PASS2,
-                                  ACPI_NS_NO_UPSEARCH, walk_state, &(node));
+                                  object_type, ACPI_IMODE_LOAD_PASS2, flags,
+                                  walk_state, &node);
                break;
        }
 
index c922897..3927c49 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7817e55..16c8e38 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 90990a4..688e83a 100644 (file)
@@ -615,20 +615,28 @@ static acpi_status
 find_dock_devices(acpi_handle handle, u32 lvl, void *context, void **rv)
 {
        acpi_status status;
-       acpi_handle tmp;
+       acpi_handle tmp, parent;
        struct dock_station *ds = context;
        struct dock_dependent_device *dd;
 
        status = acpi_bus_get_ejd(handle, &tmp);
-       if (ACPI_FAILURE(status))
-               return AE_OK;
+       if (ACPI_FAILURE(status)) {
+               /* try the parent device as well */
+               status = acpi_get_parent(handle, &parent);
+               if (ACPI_FAILURE(status))
+                       goto fdd_out;
+               /* see if parent is dependent on dock */
+               status = acpi_bus_get_ejd(parent, &tmp);
+               if (ACPI_FAILURE(status))
+                       goto fdd_out;
+       }
 
        if (tmp == ds->handle) {
                dd = alloc_dock_dependent_device(handle);
                if (dd)
                        add_dock_dependent_device(ds, dd);
        }
-
+fdd_out:
        return AE_OK;
 }
 
index cbdf031..743ce27 100644 (file)
@@ -872,9 +872,8 @@ static int __init acpi_ec_get_real_ecdt(void)
        acpi_status status;
        struct acpi_table_ecdt *ecdt_ptr;
 
-       status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
-                                        (struct acpi_table_header **)
-                                        &ecdt_ptr);
+       status = acpi_get_table(ACPI_SIG_ECDT, 1,
+                               (struct acpi_table_header **)&ecdt_ptr);
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
@@ -891,14 +890,14 @@ static int __init acpi_ec_get_real_ecdt(void)
        if (acpi_ec_mode == EC_INTR) {
                init_waitqueue_head(&ec_ecdt->wait);
        }
-       ec_ecdt->command_addr = ecdt_ptr->ec_control.address;
-       ec_ecdt->data_addr = ecdt_ptr->ec_data.address;
-       ec_ecdt->gpe = ecdt_ptr->gpe_bit;
+       ec_ecdt->command_addr = ecdt_ptr->control.address;
+       ec_ecdt->data_addr = ecdt_ptr->data.address;
+       ec_ecdt->gpe = ecdt_ptr->gpe;
        /* use the GL just to be safe */
        ec_ecdt->global_lock = TRUE;
        ec_ecdt->uid = ecdt_ptr->uid;
 
-       status = acpi_get_handle(NULL, ecdt_ptr->ec_id, &ec_ecdt->handle);
+       status = acpi_get_handle(NULL, ecdt_ptr->id, &ec_ecdt->handle);
        if (ACPI_FAILURE(status)) {
                goto error;
        }
index 919037d..a1f87b5 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -70,13 +70,6 @@ acpi_status acpi_ev_initialize_events(void)
 
        ACPI_FUNCTION_TRACE(ev_initialize_events);
 
-       /* Make sure we have ACPI tables */
-
-       if (!acpi_gbl_DSDT) {
-               ACPI_WARNING((AE_INFO, "No ACPI tables present!"));
-               return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-       }
-
        /*
         * Initialize the Fixed and General Purpose Events. This is done prior to
         * enabling SCIs to prevent interrupts from occurring before the handlers are
@@ -211,8 +204,7 @@ static acpi_status acpi_ev_fixed_event_initialize(void)
                if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) {
                        status =
                            acpi_set_register(acpi_gbl_fixed_event_info[i].
-                                             enable_register_id, 0,
-                                             ACPI_MTX_LOCK);
+                                             enable_register_id, 0);
                        if (ACPI_FAILURE(status)) {
                                return (status);
                        }
@@ -298,7 +290,7 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event)
        /* Clear the status bit */
 
        (void)acpi_set_register(acpi_gbl_fixed_event_info[event].
-                               status_register_id, 1, ACPI_MTX_DO_NOT_LOCK);
+                               status_register_id, 1);
 
        /*
         * Make sure we've got a handler.  If not, report an error.
@@ -306,8 +298,7 @@ static u32 acpi_ev_fixed_event_dispatch(u32 event)
         */
        if (NULL == acpi_gbl_fixed_event_handlers[event].handler) {
                (void)acpi_set_register(acpi_gbl_fixed_event_info[event].
-                                       enable_register_id, 0,
-                                       ACPI_MTX_DO_NOT_LOCK);
+                                       enable_register_id, 0);
 
                ACPI_ERROR((AE_INFO,
                            "No installed handler for fixed event [%08X]",
index c76c058..dfac3ec 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -121,7 +121,9 @@ acpi_ev_update_gpe_enable_masks(struct acpi_gpe_event_info *gpe_event_info,
        if (!gpe_register_info) {
                return_ACPI_STATUS(AE_NOT_EXIST);
        }
-       register_bit = gpe_event_info->register_bit;
+       register_bit = (u8)
+           (1 <<
+            (gpe_event_info->gpe_number - gpe_register_info->base_gpe_number));
 
        /* 1) Disable case.  Simply clear all enable bits */
 
@@ -458,8 +460,7 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info * gpe_xrupt_list)
 
                                /* Examine one GPE bit */
 
-                               if (enabled_status_byte &
-                                   acpi_gbl_decode_to8bit[j]) {
+                               if (enabled_status_byte & (1 << j)) {
                                        /*
                                         * Found an active GPE. Dispatch the event to a handler
                                         * or method.
@@ -570,7 +571,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
 
                if (ACPI_FAILURE(status)) {
                        ACPI_EXCEPTION((AE_INFO, status,
-                                       "While evaluating GPE method [%4.4s]",
+                                       "while evaluating GPE method [%4.4s]",
                                        acpi_ut_get_node_name
                                        (local_gpe_event_info.dispatch.
                                         method_node)));
@@ -618,6 +619,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
 
        ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
 
+       acpi_gpe_count++;
+
        /*
         * If edge-triggered, clear the GPE status bit now.  Note that
         * level-triggered events are cleared after the GPE is serviced.
@@ -633,20 +636,23 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
                }
        }
 
-       /* Save current system state */
-
-       if (acpi_gbl_system_awake_and_running) {
-               ACPI_SET_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
-       } else {
-               ACPI_CLEAR_BIT(gpe_event_info->flags, ACPI_GPE_SYSTEM_RUNNING);
+       if (!acpi_gbl_system_awake_and_running) {
+               /*
+                * We just woke up because of a wake GPE. Disable any further GPEs
+                * until we are fully up and running (Only wake GPEs should be enabled
+                * at this time, but we just brute-force disable them all.)
+                * 1) We must disable this particular wake GPE so it won't fire again
+                * 2) We want to disable all wake GPEs, since we are now awake
+                */
+               (void)acpi_hw_disable_all_gpes();
        }
 
        /*
-        * Dispatch the GPE to either an installed handler, or the control
-        * method associated with this GPE (_Lxx or _Exx).
-        * If a handler exists, we invoke it and do not attempt to run the method.
-        * If there is neither a handler nor a method, we disable the level to
-        * prevent further events from coming in here.
+        * Dispatch the GPE to either an installed handler, or the control method
+        * associated with this GPE (_Lxx or _Exx). If a handler exists, we invoke
+        * it and do not attempt to run the method. If there is neither a handler
+        * nor a method, we disable this GPE to prevent further such pointless
+        * events from firing.
         */
        switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
        case ACPI_GPE_DISPATCH_HANDLER:
@@ -677,8 +683,8 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
        case ACPI_GPE_DISPATCH_METHOD:
 
                /*
-                * Disable GPE, so it doesn't keep firing before the method has a
-                * chance to run.
+                * Disable the GPE, so it doesn't keep firing before the method has a
+                * chance to run (it runs asynchronously with interrupts enabled).
                 */
                status = acpi_ev_disable_gpe(gpe_event_info);
                if (ACPI_FAILURE(status)) {
@@ -711,7 +717,7 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
                            gpe_number));
 
                /*
-                * Disable the GPE.  The GPE will remain disabled until the ACPI
+                * Disable the GPE. The GPE will remain disabled until the ACPI
                 * Core Subsystem is restarted, or a handler is installed.
                 */
                status = acpi_ev_disable_gpe(gpe_event_info);
@@ -726,50 +732,3 @@ acpi_ev_gpe_dispatch(struct acpi_gpe_event_info *gpe_event_info, u32 gpe_number)
 
        return_UINT32(ACPI_INTERRUPT_HANDLED);
 }
-
-#ifdef ACPI_GPE_NOTIFY_CHECK
-/*******************************************************************************
- * TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED
- *
- * FUNCTION:    acpi_ev_check_for_wake_only_gpe
- *
- * PARAMETERS:  gpe_event_info  - info for this GPE
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Determine if a a GPE is "wake-only".
- *
- *              Called from Notify() code in interpreter when a "DeviceWake"
- *              Notify comes in.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ev_check_for_wake_only_gpe(struct acpi_gpe_event_info *gpe_event_info)
-{
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE(ev_check_for_wake_only_gpe);
-
-       if ((gpe_event_info) && /* Only >0 for _Lxx/_Exx */
-           ((gpe_event_info->flags & ACPI_GPE_SYSTEM_MASK) == ACPI_GPE_SYSTEM_RUNNING)) {      /* System state at GPE time */
-               /* This must be a wake-only GPE, disable it */
-
-               status = acpi_ev_disable_gpe(gpe_event_info);
-
-               /* Set GPE to wake-only.  Do not change wake disabled/enabled status */
-
-               acpi_ev_set_gpe_type(gpe_event_info, ACPI_GPE_TYPE_WAKE);
-
-               ACPI_INFO((AE_INFO,
-                          "GPE %p was updated from wake/run to wake-only",
-                          gpe_event_info));
-
-               /* This was a wake-only GPE */
-
-               return_ACPI_STATUS(AE_WAKE_ONLY_GPE);
-       }
-
-       return_ACPI_STATUS(AE_OK);
-}
-#endif
index 95ddeb4..ad5bc76 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -529,7 +529,7 @@ static struct acpi_gpe_xrupt_info *acpi_ev_get_gpe_xrupt_block(u32
 
        /* Install new interrupt handler if not SCI_INT */
 
-       if (interrupt_number != acpi_gbl_FADT->sci_int) {
+       if (interrupt_number != acpi_gbl_FADT.sci_interrupt) {
                status = acpi_os_install_interrupt_handler(interrupt_number,
                                                           acpi_ev_gpe_xrupt_handler,
                                                           gpe_xrupt);
@@ -567,7 +567,7 @@ acpi_ev_delete_gpe_xrupt(struct acpi_gpe_xrupt_info *gpe_xrupt)
 
        /* We never want to remove the SCI interrupt handler */
 
-       if (gpe_xrupt->interrupt_number == acpi_gbl_FADT->sci_int) {
+       if (gpe_xrupt->interrupt_number == acpi_gbl_FADT.sci_interrupt) {
                gpe_xrupt->gpe_block_list_head = NULL;
                return_ACPI_STATUS(AE_OK);
        }
@@ -796,30 +796,31 @@ acpi_ev_create_gpe_info_blocks(struct acpi_gpe_block_info *gpe_block)
                    (u8) (gpe_block->block_base_number +
                          (i * ACPI_GPE_REGISTER_WIDTH));
 
-               ACPI_STORE_ADDRESS(this_register->status_address.address,
-                                  (gpe_block->block_address.address + i));
+               this_register->status_address.address =
+                   gpe_block->block_address.address + i;
 
-               ACPI_STORE_ADDRESS(this_register->enable_address.address,
-                                  (gpe_block->block_address.address
-                                   + i + gpe_block->register_count));
+               this_register->enable_address.address =
+                   gpe_block->block_address.address + i +
+                   gpe_block->register_count;
 
-               this_register->status_address.address_space_id =
-                   gpe_block->block_address.address_space_id;
-               this_register->enable_address.address_space_id =
-                   gpe_block->block_address.address_space_id;
-               this_register->status_address.register_bit_width =
+               this_register->status_address.space_id =
+                   gpe_block->block_address.space_id;
+               this_register->enable_address.space_id =
+                   gpe_block->block_address.space_id;
+               this_register->status_address.bit_width =
                    ACPI_GPE_REGISTER_WIDTH;
-               this_register->enable_address.register_bit_width =
+               this_register->enable_address.bit_width =
                    ACPI_GPE_REGISTER_WIDTH;
-               this_register->status_address.register_bit_offset =
+               this_register->status_address.bit_offset =
                    ACPI_GPE_REGISTER_WIDTH;
-               this_register->enable_address.register_bit_offset =
+               this_register->enable_address.bit_offset =
                    ACPI_GPE_REGISTER_WIDTH;
 
                /* Init the event_info for each GPE within this register */
 
                for (j = 0; j < ACPI_GPE_REGISTER_WIDTH; j++) {
-                       this_event->register_bit = acpi_gbl_decode_to8bit[j];
+                       this_event->gpe_number =
+                           (u8) (this_register->base_gpe_number + j);
                        this_event->register_info = this_register;
                        this_event++;
                }
@@ -1109,11 +1110,12 @@ acpi_status acpi_ev_gpe_initialize(void)
         * If EITHER the register length OR the block address are zero, then that
         * particular block is not supported.
         */
-       if (acpi_gbl_FADT->gpe0_blk_len && acpi_gbl_FADT->xgpe0_blk.address) {
+       if (acpi_gbl_FADT.gpe0_block_length &&
+           acpi_gbl_FADT.xgpe0_block.address) {
 
                /* GPE block 0 exists (has both length and address > 0) */
 
-               register_count0 = (u16) (acpi_gbl_FADT->gpe0_blk_len / 2);
+               register_count0 = (u16) (acpi_gbl_FADT.gpe0_block_length / 2);
 
                gpe_number_max =
                    (register_count0 * ACPI_GPE_REGISTER_WIDTH) - 1;
@@ -1121,9 +1123,9 @@ acpi_status acpi_ev_gpe_initialize(void)
                /* Install GPE Block 0 */
 
                status = acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
-                                                 &acpi_gbl_FADT->xgpe0_blk,
+                                                 &acpi_gbl_FADT.xgpe0_block,
                                                  register_count0, 0,
-                                                 acpi_gbl_FADT->sci_int,
+                                                 acpi_gbl_FADT.sci_interrupt,
                                                  &acpi_gbl_gpe_fadt_blocks[0]);
 
                if (ACPI_FAILURE(status)) {
@@ -1132,20 +1134,21 @@ acpi_status acpi_ev_gpe_initialize(void)
                }
        }
 
-       if (acpi_gbl_FADT->gpe1_blk_len && acpi_gbl_FADT->xgpe1_blk.address) {
+       if (acpi_gbl_FADT.gpe1_block_length &&
+           acpi_gbl_FADT.xgpe1_block.address) {
 
                /* GPE block 1 exists (has both length and address > 0) */
 
-               register_count1 = (u16) (acpi_gbl_FADT->gpe1_blk_len / 2);
+               register_count1 = (u16) (acpi_gbl_FADT.gpe1_block_length / 2);
 
                /* Check for GPE0/GPE1 overlap (if both banks exist) */
 
                if ((register_count0) &&
-                   (gpe_number_max >= acpi_gbl_FADT->gpe1_base)) {
+                   (gpe_number_max >= acpi_gbl_FADT.gpe1_base)) {
                        ACPI_ERROR((AE_INFO,
                                    "GPE0 block (GPE 0 to %d) overlaps the GPE1 block (GPE %d to %d) - Ignoring GPE1",
-                                   gpe_number_max, acpi_gbl_FADT->gpe1_base,
-                                   acpi_gbl_FADT->gpe1_base +
+                                   gpe_number_max, acpi_gbl_FADT.gpe1_base,
+                                   acpi_gbl_FADT.gpe1_base +
                                    ((register_count1 *
                                      ACPI_GPE_REGISTER_WIDTH) - 1)));
 
@@ -1157,10 +1160,11 @@ acpi_status acpi_ev_gpe_initialize(void)
 
                        status =
                            acpi_ev_create_gpe_block(acpi_gbl_fadt_gpe_device,
-                                                    &acpi_gbl_FADT->xgpe1_blk,
+                                                    &acpi_gbl_FADT.xgpe1_block,
                                                     register_count1,
-                                                    acpi_gbl_FADT->gpe1_base,
-                                                    acpi_gbl_FADT->sci_int,
+                                                    acpi_gbl_FADT.gpe1_base,
+                                                    acpi_gbl_FADT.
+                                                    sci_interrupt,
                                                     &acpi_gbl_gpe_fadt_blocks
                                                     [1]);
 
@@ -1173,7 +1177,7 @@ acpi_status acpi_ev_gpe_initialize(void)
                         * GPE0 and GPE1 do not have to be contiguous in the GPE number
                         * space. However, GPE0 always starts at GPE number zero.
                         */
-                       gpe_number_max = acpi_gbl_FADT->gpe1_base +
+                       gpe_number_max = acpi_gbl_FADT.gpe1_base +
                            ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1);
                }
        }
index bf63edc..1b784ff 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -63,14 +63,18 @@ static const char *acpi_notify_value_names[] = {
 };
 #endif
 
+/* Pointer to FACS needed for the Global Lock */
+
+static struct acpi_table_facs *facs = NULL;
+
 /* Local prototypes */
 
 static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context);
 
-static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context);
-
 static u32 acpi_ev_global_lock_handler(void *context);
 
+static acpi_status acpi_ev_remove_global_lock_handler(void);
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_is_notify_object
@@ -280,51 +284,21 @@ static void ACPI_SYSTEM_XFACE acpi_ev_notify_dispatch(void *context)
        acpi_ut_delete_generic_state(notify_info);
 }
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ev_global_lock_thread
- *
- * PARAMETERS:  Context         - From thread interface, not used
- *
- * RETURN:      None
- *
- * DESCRIPTION: Invoked by SCI interrupt handler upon acquisition of the
- *              Global Lock.  Simply signal all threads that are waiting
- *              for the lock.
- *
- ******************************************************************************/
-
-static void ACPI_SYSTEM_XFACE acpi_ev_global_lock_thread(void *context)
-{
-       acpi_status status;
-
-       /* Signal threads that are waiting for the lock */
-
-       if (acpi_gbl_global_lock_thread_count) {
-
-               /* Send sufficient units to the semaphore */
-
-               status =
-                   acpi_os_signal_semaphore(acpi_gbl_global_lock_semaphore,
-                                            acpi_gbl_global_lock_thread_count);
-               if (ACPI_FAILURE(status)) {
-                       ACPI_ERROR((AE_INFO,
-                                   "Could not signal Global Lock semaphore"));
-               }
-       }
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_global_lock_handler
  *
  * PARAMETERS:  Context         - From thread interface, not used
  *
- * RETURN:      ACPI_INTERRUPT_HANDLED or ACPI_INTERRUPT_NOT_HANDLED
+ * RETURN:      ACPI_INTERRUPT_HANDLED
  *
  * DESCRIPTION: Invoked directly from the SCI handler when a global lock
- *              release interrupt occurs.  Grab the global lock and queue
- *              the global lock thread for execution
+ *              release interrupt occurs. Attempt to acquire the global lock,
+ *              if successful, signal the thread waiting for the lock.
+ *
+ * NOTE: Assumes that the semaphore can be signaled from interrupt level. If
+ * this is not possible for some reason, a separate thread will have to be
+ * scheduled to do this.
  *
  ******************************************************************************/
 
@@ -333,16 +307,24 @@ static u32 acpi_ev_global_lock_handler(void *context)
        u8 acquired = FALSE;
 
        /*
-        * Attempt to get the lock
+        * Attempt to get the lock.
+        *
         * If we don't get it now, it will be marked pending and we will
         * take another interrupt when it becomes free.
         */
-       ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
+       ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
        if (acquired) {
 
                /* Got the lock, now wake all threads waiting for it */
+
                acpi_gbl_global_lock_acquired = TRUE;
-               acpi_ev_global_lock_thread(context);
+               /* Send a unit to the semaphore */
+
+               if (ACPI_FAILURE(acpi_os_signal_semaphore(
+                       acpi_gbl_global_lock_semaphore, 1))) {
+                       ACPI_ERROR((AE_INFO,
+                                   "Could not signal Global Lock semaphore"));
+               }
        }
 
        return (ACPI_INTERRUPT_HANDLED);
@@ -366,6 +348,13 @@ acpi_status acpi_ev_init_global_lock_handler(void)
 
        ACPI_FUNCTION_TRACE(ev_init_global_lock_handler);
 
+       status =
+           acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+                                   (struct acpi_table_header **)&facs);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
        acpi_gbl_global_lock_present = TRUE;
        status = acpi_install_fixed_event_handler(ACPI_EVENT_GLOBAL,
                                                  acpi_ev_global_lock_handler,
@@ -389,6 +378,31 @@ acpi_status acpi_ev_init_global_lock_handler(void)
        return_ACPI_STATUS(status);
 }
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_remove_global_lock_handler
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Remove the handler for the Global Lock
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_ev_remove_global_lock_handler(void)
+{
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE(ev_remove_global_lock_handler);
+
+       acpi_gbl_global_lock_present = FALSE;
+       status = acpi_remove_fixed_event_handler(ACPI_EVENT_GLOBAL,
+                                                acpi_ev_global_lock_handler);
+
+       return_ACPI_STATUS(status);
+}
+
 /******************************************************************************
  *
  * FUNCTION:    acpi_ev_acquire_global_lock
@@ -399,6 +413,16 @@ acpi_status acpi_ev_init_global_lock_handler(void)
  *
  * DESCRIPTION: Attempt to gain ownership of the Global Lock.
  *
+ * MUTEX:       Interpreter must be locked
+ *
+ * Note: The original implementation allowed multiple threads to "acquire" the
+ * Global Lock, and the OS would hold the lock until the last thread had
+ * released it. However, this could potentially starve the BIOS out of the
+ * lock, especially in the case where there is a tight handshake between the
+ * Embedded Controller driver and the BIOS. Therefore, this implementation
+ * allows only one thread to acquire the HW Global Lock at a time, and makes
+ * the global lock appear as a standard mutex on the OS side.
+ *
  *****************************************************************************/
 
 acpi_status acpi_ev_acquire_global_lock(u16 timeout)
@@ -408,53 +432,51 @@ acpi_status acpi_ev_acquire_global_lock(u16 timeout)
 
        ACPI_FUNCTION_TRACE(ev_acquire_global_lock);
 
-#ifndef ACPI_APPLICATION
-       /* Make sure that we actually have a global lock */
-
-       if (!acpi_gbl_global_lock_present) {
-               return_ACPI_STATUS(AE_NO_GLOBAL_LOCK);
+       /*
+        * Only one thread can acquire the GL at a time, the global_lock_mutex
+        * enforces this. This interface releases the interpreter if we must wait.
+        */
+       status = acpi_ex_system_wait_mutex(acpi_gbl_global_lock_mutex, timeout);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
        }
-#endif
-
-       /* One more thread wants the global lock */
-
-       acpi_gbl_global_lock_thread_count++;
 
        /*
-        * If we (OS side vs. BIOS side) have the hardware lock already,
-        * we are done
+        * Make sure that a global lock actually exists. If not, just treat
+        * the lock as a standard mutex.
         */
-       if (acpi_gbl_global_lock_acquired) {
+       if (!acpi_gbl_global_lock_present) {
+               acpi_gbl_global_lock_acquired = TRUE;
                return_ACPI_STATUS(AE_OK);
        }
 
-       /* We must acquire the actual hardware lock */
+       /* Attempt to acquire the actual hardware lock */
 
-       ACPI_ACQUIRE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, acquired);
+       ACPI_ACQUIRE_GLOBAL_LOCK(facs, acquired);
        if (acquired) {
 
                /* We got the lock */
 
                ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-                                 "Acquired the HW Global Lock\n"));
+                                 "Acquired hardware Global Lock\n"));
 
                acpi_gbl_global_lock_acquired = TRUE;
                return_ACPI_STATUS(AE_OK);
        }
 
        /*
-        * Did not get the lock.  The pending bit was set above, and we must now
+        * Did not get the lock. The pending bit was set above, and we must now
         * wait until we get the global lock released interrupt.
         */
-       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for the HW Global Lock\n"));
+       ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Waiting for hardware Global Lock\n"));
 
        /*
-        * Acquire the global lock semaphore first.
-        * Since this wait will block, we must release the interpreter
+        * Wait for handshake with the global lock interrupt handler.
+        * This interface releases the interpreter if we must wait.
         */
-       status =
-           acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
-                                         timeout);
+       status = acpi_ex_system_wait_semaphore(acpi_gbl_global_lock_semaphore,
+                                              ACPI_WAIT_FOREVER);
+
        return_ACPI_STATUS(status);
 }
 
@@ -477,38 +499,39 @@ acpi_status acpi_ev_release_global_lock(void)
 
        ACPI_FUNCTION_TRACE(ev_release_global_lock);
 
-       if (!acpi_gbl_global_lock_thread_count) {
+       /* Lock must be already acquired */
+
+       if (!acpi_gbl_global_lock_acquired) {
                ACPI_WARNING((AE_INFO,
-                             "Cannot release HW Global Lock, it has not been acquired"));
+                             "Cannot release the ACPI Global Lock, it has not been acquired"));
                return_ACPI_STATUS(AE_NOT_ACQUIRED);
        }
 
-       /* One fewer thread has the global lock */
+       if (acpi_gbl_global_lock_present) {
 
-       acpi_gbl_global_lock_thread_count--;
-       if (acpi_gbl_global_lock_thread_count) {
+               /* Allow any thread to release the lock */
 
-               /* There are still some threads holding the lock, cannot release */
+               ACPI_RELEASE_GLOBAL_LOCK(facs, pending);
 
-               return_ACPI_STATUS(AE_OK);
+               /*
+                * If the pending bit was set, we must write GBL_RLS to the control
+                * register
+                */
+               if (pending) {
+                       status =
+                           acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
+                                             1);
+               }
+
+               ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+                                 "Released hardware Global Lock\n"));
        }
 
-       /*
-        * No more threads holding lock, we can do the actual hardware
-        * release
-        */
-       ACPI_RELEASE_GLOBAL_LOCK(acpi_gbl_common_fACS.global_lock, pending);
        acpi_gbl_global_lock_acquired = FALSE;
 
-       /*
-        * If the pending bit was set, we must write GBL_RLS to the control
-        * register
-        */
-       if (pending) {
-               status = acpi_set_register(ACPI_BITREG_GLOBAL_LOCK_RELEASE,
-                                          1, ACPI_MTX_LOCK);
-       }
+       /* Release the local GL mutex */
 
+       acpi_os_release_mutex(acpi_gbl_global_lock_mutex);
        return_ACPI_STATUS(status);
 }
 
@@ -558,6 +581,12 @@ void acpi_ev_terminate(void)
                if (ACPI_FAILURE(status)) {
                        ACPI_ERROR((AE_INFO, "Could not remove SCI handler"));
                }
+
+               status = acpi_ev_remove_global_lock_handler();
+               if (ACPI_FAILURE(status)) {
+                       ACPI_ERROR((AE_INFO,
+                                   "Could not remove Global Lock handler"));
+               }
        }
 
        /* Deallocate all handler objects installed within GPE info structs */
index 21caae0..e99f0c4 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -291,7 +291,6 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                               u32 bit_width, acpi_integer * value)
 {
        acpi_status status;
-       acpi_status status2;
        acpi_adr_space_handler handler;
        acpi_adr_space_setup region_setup;
        union acpi_operand_object *handler_desc;
@@ -345,7 +344,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                 * setup will potentially execute control methods
                 * (e.g., _REG method for this region)
                 */
-               acpi_ex_exit_interpreter();
+               acpi_ex_relinquish_interpreter();
 
                status = region_setup(region_obj, ACPI_REGION_ACTIVATE,
                                      handler_desc->address_space.context,
@@ -353,10 +352,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
 
                /* Re-enter the interpreter */
 
-               status2 = acpi_ex_enter_interpreter();
-               if (ACPI_FAILURE(status2)) {
-                       return_ACPI_STATUS(status2);
-               }
+               acpi_ex_reacquire_interpreter();
 
                /* Check for failure of the Region Setup */
 
@@ -409,7 +405,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                 * exit the interpreter because the handler *might* block -- we don't
                 * know what it will do, so we can't hold the lock on the intepreter.
                 */
-               acpi_ex_exit_interpreter();
+               acpi_ex_relinquish_interpreter();
        }
 
        /* Call the handler */
@@ -430,10 +426,7 @@ acpi_ev_address_space_dispatch(union acpi_operand_object *region_obj,
                 * We just returned from a non-default handler, we must re-enter the
                 * interpreter
                 */
-               status2 = acpi_ex_enter_interpreter();
-               if (ACPI_FAILURE(status2)) {
-                       return_ACPI_STATUS(status2);
-               }
+               acpi_ex_reacquire_interpreter();
        }
 
        return_ACPI_STATUS(status);
index 203d135..a4fa7e6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evrgnini")
 
+/* Local prototypes */
+static u8 acpi_ev_match_pci_root_bridge(char *id);
+
+static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node);
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_system_memory_region_setup
@@ -62,6 +67,7 @@ ACPI_MODULE_NAME("evrgnini")
  * DESCRIPTION: Setup a system_memory operation region
  *
  ******************************************************************************/
+
 acpi_status
 acpi_ev_system_memory_region_setup(acpi_handle handle,
                                   u32 function,
@@ -168,9 +174,9 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
        union acpi_operand_object *handler_obj;
        struct acpi_namespace_node *parent_node;
        struct acpi_namespace_node *pci_root_node;
+       struct acpi_namespace_node *pci_device_node;
        union acpi_operand_object *region_obj =
            (union acpi_operand_object *)handle;
-       struct acpi_device_id object_hID;
 
        ACPI_FUNCTION_TRACE(ev_pci_config_region_setup);
 
@@ -215,45 +221,30 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
 
                pci_root_node = parent_node;
                while (pci_root_node != acpi_gbl_root_node) {
-                       status =
-                           acpi_ut_execute_HID(pci_root_node, &object_hID);
-                       if (ACPI_SUCCESS(status)) {
-                               /*
-                                * Got a valid _HID string, check if this is a PCI root.
-                                * New for ACPI 3.0: check for a PCI Express root also.
-                                */
-                               if (!
-                                   (ACPI_STRNCMP
-                                    (object_hID.value, PCI_ROOT_HID_STRING,
-                                     sizeof(PCI_ROOT_HID_STRING)))
-                                   ||
-                                   !(ACPI_STRNCMP
-                                     (object_hID.value,
-                                      PCI_EXPRESS_ROOT_HID_STRING,
-                                      sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
-
-                                       /* Install a handler for this PCI root bridge */
 
-                                       status =
-                                           acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
-                                       if (ACPI_FAILURE(status)) {
-                                               if (status == AE_SAME_HANDLER) {
-                                                       /*
-                                                        * It is OK if the handler is already installed on the root
-                                                        * bridge.  Still need to return a context object for the
-                                                        * new PCI_Config operation region, however.
-                                                        */
-                                                       status = AE_OK;
-                                               } else {
-                                                       ACPI_EXCEPTION((AE_INFO,
-                                                                       status,
-                                                                       "Could not install PciConfig handler for Root Bridge %4.4s",
-                                                                       acpi_ut_get_node_name
-                                                                       (pci_root_node)));
-                                               }
+                       /* Get the _HID/_CID in order to detect a root_bridge */
+
+                       if (acpi_ev_is_pci_root_bridge(pci_root_node)) {
+
+                               /* Install a handler for this PCI root bridge */
+
+                               status = acpi_install_address_space_handler((acpi_handle) pci_root_node, ACPI_ADR_SPACE_PCI_CONFIG, ACPI_DEFAULT_HANDLER, NULL, NULL);
+                               if (ACPI_FAILURE(status)) {
+                                       if (status == AE_SAME_HANDLER) {
+                                               /*
+                                                * It is OK if the handler is already installed on the root
+                                                * bridge.  Still need to return a context object for the
+                                                * new PCI_Config operation region, however.
+                                                */
+                                               status = AE_OK;
+                                       } else {
+                                               ACPI_EXCEPTION((AE_INFO, status,
+                                                               "Could not install PciConfig handler for Root Bridge %4.4s",
+                                                               acpi_ut_get_node_name
+                                                               (pci_root_node)));
                                        }
-                                       break;
                                }
+                               break;
                        }
 
                        pci_root_node = acpi_ns_get_parent_node(pci_root_node);
@@ -282,14 +273,25 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
        /*
         * For PCI_Config space access, we need the segment, bus,
         * device and function numbers.  Acquire them here.
+        *
+        * Find the parent device object. (This allows the operation region to be
+        * within a subscope under the device, such as a control method.)
         */
+       pci_device_node = region_obj->region.node;
+       while (pci_device_node && (pci_device_node->type != ACPI_TYPE_DEVICE)) {
+               pci_device_node = acpi_ns_get_parent_node(pci_device_node);
+       }
+
+       if (!pci_device_node) {
+               return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+       }
 
        /*
         * Get the PCI device and function numbers from the _ADR object
         * contained in the parent's scope.
         */
        status =
-           acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, parent_node,
+           acpi_ut_evaluate_numeric_object(METHOD_NAME__ADR, pci_device_node,
                                            &pci_value);
 
        /*
@@ -327,6 +329,91 @@ acpi_ev_pci_config_region_setup(acpi_handle handle,
        return_ACPI_STATUS(AE_OK);
 }
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_match_pci_root_bridge
+ *
+ * PARAMETERS:  Id              - The HID/CID in string format
+ *
+ * RETURN:      TRUE if the Id is a match for a PCI/PCI-Express Root Bridge
+ *
+ * DESCRIPTION: Determine if the input ID is a PCI Root Bridge ID.
+ *
+ ******************************************************************************/
+
+static u8 acpi_ev_match_pci_root_bridge(char *id)
+{
+
+       /*
+        * Check if this is a PCI root.
+        * ACPI 3.0+: check for a PCI Express root also.
+        */
+       if (!(ACPI_STRNCMP(id,
+                          PCI_ROOT_HID_STRING,
+                          sizeof(PCI_ROOT_HID_STRING))) ||
+           !(ACPI_STRNCMP(id,
+                          PCI_EXPRESS_ROOT_HID_STRING,
+                          sizeof(PCI_EXPRESS_ROOT_HID_STRING)))) {
+               return (TRUE);
+       }
+
+       return (FALSE);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ev_is_pci_root_bridge
+ *
+ * PARAMETERS:  Node            - Device node being examined
+ *
+ * RETURN:      TRUE if device is a PCI/PCI-Express Root Bridge
+ *
+ * DESCRIPTION: Determine if the input device represents a PCI Root Bridge by
+ *              examining the _HID and _CID for the device.
+ *
+ ******************************************************************************/
+
+static u8 acpi_ev_is_pci_root_bridge(struct acpi_namespace_node *node)
+{
+       acpi_status status;
+       struct acpi_device_id hid;
+       struct acpi_compatible_id_list *cid;
+       acpi_native_uint i;
+
+       /*
+        * Get the _HID and check for a PCI Root Bridge
+        */
+       status = acpi_ut_execute_HID(node, &hid);
+       if (ACPI_FAILURE(status)) {
+               return (FALSE);
+       }
+
+       if (acpi_ev_match_pci_root_bridge(hid.value)) {
+               return (TRUE);
+       }
+
+       /*
+        * The _HID did not match.
+        * Get the _CID and check for a PCI Root Bridge
+        */
+       status = acpi_ut_execute_CID(node, &cid);
+       if (ACPI_FAILURE(status)) {
+               return (FALSE);
+       }
+
+       /* Check all _CIDs in the returned list */
+
+       for (i = 0; i < cid->count; i++) {
+               if (acpi_ev_match_pci_root_bridge(cid->id[i].value)) {
+                       ACPI_FREE(cid);
+                       return (TRUE);
+               }
+       }
+
+       ACPI_FREE(cid);
+       return (FALSE);
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ev_pci_bar_region_setup
@@ -432,6 +519,9 @@ acpi_ev_default_region_setup(acpi_handle handle,
  *              a PCI address in the scope of the definition.  This address is
  *              required to perform an access to PCI config space.
  *
+ * MUTEX:       Interpreter should be unlocked, because we may run the _REG
+ *              method for this region.
+ *
  ******************************************************************************/
 
 acpi_status
index 8106215..7e5d15c 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -142,9 +142,10 @@ u32 acpi_ev_install_sci_handler(void)
 
        ACPI_FUNCTION_TRACE(ev_install_sci_handler);
 
-       status = acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT->sci_int,
-                                                  acpi_ev_sci_xrupt_handler,
-                                                  acpi_gbl_gpe_xrupt_list_head);
+       status =
+           acpi_os_install_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
+                                             acpi_ev_sci_xrupt_handler,
+                                             acpi_gbl_gpe_xrupt_list_head);
        return_ACPI_STATUS(status);
 }
 
@@ -175,8 +176,9 @@ acpi_status acpi_ev_remove_sci_handler(void)
 
        /* Just let the OS remove the handler and disable the level */
 
-       status = acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT->sci_int,
-                                                 acpi_ev_sci_xrupt_handler);
+       status =
+           acpi_os_remove_interrupt_handler((u32) acpi_gbl_FADT.sci_interrupt,
+                                            acpi_ev_sci_xrupt_handler);
 
        return_ACPI_STATUS(status);
 }
index 923fd2b..685a103 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -768,11 +768,9 @@ acpi_status acpi_acquire_global_lock(u16 timeout, u32 * handle)
                return (AE_BAD_PARAMETER);
        }
 
-       status = acpi_ex_enter_interpreter();
-       if (ACPI_FAILURE(status)) {
-               return (status);
-       }
+       /* Must lock interpreter to prevent race conditions */
 
+       acpi_ex_enter_interpreter();
        status = acpi_ev_acquire_global_lock(timeout);
        acpi_ex_exit_interpreter();
 
index 7ebc2ef..17065e9 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
 #include <acpi/acpi.h>
 #include <acpi/acevents.h>
 #include <acpi/acnamesp.h>
+#include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_EVENTS
 ACPI_MODULE_NAME("evxfevnt")
@@ -65,13 +66,14 @@ acpi_status acpi_enable(void)
 
        ACPI_FUNCTION_TRACE(acpi_enable);
 
-       /* Make sure we have the FADT */
+       /* ACPI tables must be present */
 
-       if (!acpi_gbl_FADT) {
-               ACPI_WARNING((AE_INFO, "No FADT information present!"));
+       if (!acpi_tb_tables_loaded()) {
                return_ACPI_STATUS(AE_NO_ACPI_TABLES);
        }
 
+       /* Check current mode */
+
        if (acpi_hw_get_mode() == ACPI_SYS_MODE_ACPI) {
                ACPI_DEBUG_PRINT((ACPI_DB_INIT,
                                  "System is already in ACPI mode\n"));
@@ -111,11 +113,6 @@ acpi_status acpi_disable(void)
 
        ACPI_FUNCTION_TRACE(acpi_disable);
 
-       if (!acpi_gbl_FADT) {
-               ACPI_WARNING((AE_INFO, "No FADT information present!"));
-               return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-       }
-
        if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) {
                ACPI_DEBUG_PRINT((ACPI_DB_INIT,
                                  "System is already in legacy (non-ACPI) mode\n"));
@@ -169,7 +166,7 @@ acpi_status acpi_enable_event(u32 event, u32 flags)
         */
        status =
            acpi_set_register(acpi_gbl_fixed_event_info[event].
-                             enable_register_id, 1, ACPI_MTX_LOCK);
+                             enable_register_id, 1);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
@@ -178,7 +175,7 @@ acpi_status acpi_enable_event(u32 event, u32 flags)
 
        status =
            acpi_get_register(acpi_gbl_fixed_event_info[event].
-                             enable_register_id, &value, ACPI_MTX_LOCK);
+                             enable_register_id, &value);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
@@ -368,14 +365,14 @@ acpi_status acpi_disable_event(u32 event, u32 flags)
         */
        status =
            acpi_set_register(acpi_gbl_fixed_event_info[event].
-                             enable_register_id, 0, ACPI_MTX_LOCK);
+                             enable_register_id, 0);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
 
        status =
            acpi_get_register(acpi_gbl_fixed_event_info[event].
-                             enable_register_id, &value, ACPI_MTX_LOCK);
+                             enable_register_id, &value);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
@@ -421,7 +418,7 @@ acpi_status acpi_clear_event(u32 event)
         */
        status =
            acpi_set_register(acpi_gbl_fixed_event_info[event].
-                             status_register_id, 1, ACPI_MTX_LOCK);
+                             status_register_id, 1);
 
        return_ACPI_STATUS(status);
 }
@@ -510,7 +507,7 @@ acpi_status acpi_get_event_status(u32 event, acpi_event_status * event_status)
 
        status =
            acpi_get_register(acpi_gbl_fixed_event_info[event].
-                             status_register_id, event_status, ACPI_MTX_LOCK);
+                             status_register_id, event_status);
 
        return_ACPI_STATUS(status);
 }
index 83b12a9..7bf09c5 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index c8341fa..25802f3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,7 +54,7 @@ ACPI_MODULE_NAME("exconfig")
 
 /* Local prototypes */
 static acpi_status
-acpi_ex_add_table(struct acpi_table_header *table,
+acpi_ex_add_table(acpi_native_uint table_index,
                  struct acpi_namespace_node *parent_node,
                  union acpi_operand_object **ddb_handle);
 
@@ -74,12 +74,11 @@ acpi_ex_add_table(struct acpi_table_header *table,
  ******************************************************************************/
 
 static acpi_status
-acpi_ex_add_table(struct acpi_table_header *table,
+acpi_ex_add_table(acpi_native_uint table_index,
                  struct acpi_namespace_node *parent_node,
                  union acpi_operand_object **ddb_handle)
 {
        acpi_status status;
-       struct acpi_table_desc table_info;
        union acpi_operand_object *obj_desc;
 
        ACPI_FUNCTION_TRACE(ex_add_table);
@@ -98,42 +97,16 @@ acpi_ex_add_table(struct acpi_table_header *table,
 
        /* Install the new table into the local data structures */
 
-       ACPI_MEMSET(&table_info, 0, sizeof(struct acpi_table_desc));
-
-       table_info.type = ACPI_TABLE_ID_SSDT;
-       table_info.pointer = table;
-       table_info.length = (acpi_size) table->length;
-       table_info.allocation = ACPI_MEM_ALLOCATED;
-
-       status = acpi_tb_install_table(&table_info);
-       obj_desc->reference.object = table_info.installed_desc;
-
-       if (ACPI_FAILURE(status)) {
-               if (status == AE_ALREADY_EXISTS) {
-
-                       /* Table already exists, just return the handle */
-
-                       return_ACPI_STATUS(AE_OK);
-               }
-               goto cleanup;
-       }
+       obj_desc->reference.object = ACPI_CAST_PTR(void, table_index);
 
        /* Add the table to the namespace */
 
-       status = acpi_ns_load_table(table_info.installed_desc, parent_node);
+       status = acpi_ns_load_table(table_index, parent_node);
        if (ACPI_FAILURE(status)) {
-
-               /* Uninstall table on error */
-
-               (void)acpi_tb_uninstall_table(table_info.installed_desc);
-               goto cleanup;
+               acpi_ut_remove_reference(obj_desc);
+               *ddb_handle = NULL;
        }
 
-       return_ACPI_STATUS(AE_OK);
-
-      cleanup:
-       acpi_ut_remove_reference(obj_desc);
-       *ddb_handle = NULL;
        return_ACPI_STATUS(status);
 }
 
@@ -146,7 +119,7 @@ acpi_ex_add_table(struct acpi_table_header *table,
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Load an ACPI table
+ * DESCRIPTION: Load an ACPI table from the RSDT/XSDT
  *
  ******************************************************************************/
 
@@ -156,33 +129,20 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
 {
        acpi_status status;
        union acpi_operand_object **operand = &walk_state->operands[0];
-       struct acpi_table_header *table;
+       acpi_native_uint table_index;
        struct acpi_namespace_node *parent_node;
        struct acpi_namespace_node *start_node;
        struct acpi_namespace_node *parameter_node = NULL;
        union acpi_operand_object *ddb_handle;
+       struct acpi_table_header *table;
 
        ACPI_FUNCTION_TRACE(ex_load_table_op);
 
-#if 0
-       /*
-        * Make sure that the signature does not match one of the tables that
-        * is already loaded.
-        */
-       status = acpi_tb_match_signature(operand[0]->string.pointer, NULL);
-       if (status == AE_OK) {
-
-               /* Signature matched -- don't allow override */
-
-               return_ACPI_STATUS(AE_ALREADY_EXISTS);
-       }
-#endif
-
-       /* Find the ACPI table */
+       /* Find the ACPI table in the RSDT/XSDT */
 
        status = acpi_tb_find_table(operand[0]->string.pointer,
                                    operand[1]->string.pointer,
-                                   operand[2]->string.pointer, &table);
+                                   operand[2]->string.pointer, &table_index);
        if (ACPI_FAILURE(status)) {
                if (status != AE_NOT_FOUND) {
                        return_ACPI_STATUS(status);
@@ -245,7 +205,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
 
        /* Load the table into the namespace */
 
-       status = acpi_ex_add_table(table, parent_node, &ddb_handle);
+       status = acpi_ex_add_table(table_index, parent_node, &ddb_handle);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
@@ -266,9 +226,13 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
                }
        }
 
-       ACPI_INFO((AE_INFO,
-                  "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
-                  table->signature, table->oem_id, table->oem_table_id));
+       status = acpi_get_table_by_index(table_index, &table);
+       if (ACPI_SUCCESS(status)) {
+               ACPI_INFO((AE_INFO,
+                          "Dynamic OEM Table Load - [%4.4s] OemId [%6.6s] OemTableId [%8.8s]",
+                          table->signature, table->oem_id,
+                          table->oem_table_id));
+       }
 
        *return_desc = ddb_handle;
        return_ACPI_STATUS(status);
@@ -278,7 +242,7 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
  *
  * FUNCTION:    acpi_ex_load_op
  *
- * PARAMETERS:  obj_desc        - Region or Field where the table will be
+ * PARAMETERS:  obj_desc        - Region or Buffer/Field where the table will be
  *                                obtained
  *              Target          - Where a handle to the table will be stored
  *              walk_state      - Current state
@@ -287,6 +251,12 @@ acpi_ex_load_table_op(struct acpi_walk_state *walk_state,
  *
  * DESCRIPTION: Load an ACPI table from a field or operation region
  *
+ * NOTE: Region Fields (Field, bank_field, index_fields) are resolved to buffer
+ *       objects before this code is reached.
+ *
+ *       If source is an operation region, it must refer to system_memory, as
+ *       per the ACPI specification.
+ *
  ******************************************************************************/
 
 acpi_status
@@ -294,22 +264,26 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                union acpi_operand_object *target,
                struct acpi_walk_state *walk_state)
 {
-       acpi_status status;
        union acpi_operand_object *ddb_handle;
-       union acpi_operand_object *buffer_desc = NULL;
-       struct acpi_table_header *table_ptr = NULL;
-       acpi_physical_address address;
-       struct acpi_table_header table_header;
-       acpi_integer temp;
-       u32 i;
+       struct acpi_table_desc table_desc;
+       acpi_native_uint table_index;
+       acpi_status status;
 
        ACPI_FUNCTION_TRACE(ex_load_op);
 
-       /* Object can be either an op_region or a Field */
+       ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
+
+       /* Source Object can be either an op_region or a Buffer/Field */
 
        switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
        case ACPI_TYPE_REGION:
 
+               /* Region must be system_memory (from ACPI spec) */
+
+               if (obj_desc->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+                       return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
+               }
+
                ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Region %p %s\n",
                                  obj_desc,
                                  acpi_ut_get_object_type_name(obj_desc)));
@@ -325,113 +299,41 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                        }
                }
 
-               /* Get the base physical address of the region */
-
-               address = obj_desc->region.address;
-
-               /* Get part of the table header to get the table length */
-
-               table_header.length = 0;
-               for (i = 0; i < 8; i++) {
-                       status =
-                           acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
-                                                          (acpi_physical_address)
-                                                          (i + address), 8,
-                                                          &temp);
-                       if (ACPI_FAILURE(status)) {
-                               return_ACPI_STATUS(status);
-                       }
-
-                       /* Get the one valid byte of the returned 64-bit value */
-
-                       ACPI_CAST_PTR(u8, &table_header)[i] = (u8) temp;
-               }
-
-               /* Sanity check the table length */
-
-               if (table_header.length < sizeof(struct acpi_table_header)) {
-                       return_ACPI_STATUS(AE_BAD_HEADER);
-               }
-
-               /* Allocate a buffer for the entire table */
-
-               table_ptr = ACPI_ALLOCATE(table_header.length);
-               if (!table_ptr) {
-                       return_ACPI_STATUS(AE_NO_MEMORY);
-               }
-
-               /* Get the entire table from the op region */
-
-               for (i = 0; i < table_header.length; i++) {
-                       status =
-                           acpi_ev_address_space_dispatch(obj_desc, ACPI_READ,
-                                                          (acpi_physical_address)
-                                                          (i + address), 8,
-                                                          &temp);
-                       if (ACPI_FAILURE(status)) {
-                               goto cleanup;
-                       }
-
-                       /* Get the one valid byte of the returned 64-bit value */
-
-                       ACPI_CAST_PTR(u8, table_ptr)[i] = (u8) temp;
-               }
+               table_desc.address = obj_desc->region.address;
+               table_desc.length = obj_desc->region.length;
+               table_desc.flags = ACPI_TABLE_ORIGIN_MAPPED;
                break;
 
-       case ACPI_TYPE_LOCAL_REGION_FIELD:
-       case ACPI_TYPE_LOCAL_BANK_FIELD:
-       case ACPI_TYPE_LOCAL_INDEX_FIELD:
+       case ACPI_TYPE_BUFFER:  /* Buffer or resolved region_field */
 
-               ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Load from Field %p %s\n",
-                                 obj_desc,
-                                 acpi_ut_get_object_type_name(obj_desc)));
+               /* Simply extract the buffer from the buffer object */
 
-               /*
-                * The length of the field must be at least as large as the table.
-                * Read the entire field and thus the entire table.  Buffer is
-                * allocated during the read.
-                */
-               status =
-                   acpi_ex_read_data_from_field(walk_state, obj_desc,
-                                                &buffer_desc);
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
-               }
-
-               table_ptr = ACPI_CAST_PTR(struct acpi_table_header,
-                                         buffer_desc->buffer.pointer);
-
-               /* All done with the buffer_desc, delete it */
-
-               buffer_desc->buffer.pointer = NULL;
-               acpi_ut_remove_reference(buffer_desc);
+               ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
+                                 "Load from Buffer or Field %p %s\n", obj_desc,
+                                 acpi_ut_get_object_type_name(obj_desc)));
 
-               /* Sanity check the table length */
+               table_desc.pointer = ACPI_CAST_PTR(struct acpi_table_header,
+                                                  obj_desc->buffer.pointer);
+               table_desc.length = table_desc.pointer->length;
+               table_desc.flags = ACPI_TABLE_ORIGIN_ALLOCATED;
 
-               if (table_ptr->length < sizeof(struct acpi_table_header)) {
-                       status = AE_BAD_HEADER;
-                       goto cleanup;
-               }
+               obj_desc->buffer.pointer = NULL;
                break;
 
        default:
                return_ACPI_STATUS(AE_AML_OPERAND_TYPE);
        }
 
-       /* The table must be either an SSDT or a PSDT */
-
-       if ((!ACPI_COMPARE_NAME(table_ptr->signature, PSDT_SIG)) &&
-           (!ACPI_COMPARE_NAME(table_ptr->signature, SSDT_SIG))) {
-               ACPI_ERROR((AE_INFO,
-                           "Table has invalid signature [%4.4s], must be SSDT or PSDT",
-                           table_ptr->signature));
-               status = AE_BAD_SIGNATURE;
+       /*
+        * Install the new table into the local data structures
+        */
+       status = acpi_tb_add_table(&table_desc, &table_index);
+       if (ACPI_FAILURE(status)) {
                goto cleanup;
        }
 
-       /* Install the new table into the local data structures */
-
-       status = acpi_ex_add_table(table_ptr, acpi_gbl_root_node, &ddb_handle);
+       status =
+           acpi_ex_add_table(table_index, acpi_gbl_root_node, &ddb_handle);
        if (ACPI_FAILURE(status)) {
 
                /* On error, table_ptr was deallocated above */
@@ -450,13 +352,9 @@ acpi_ex_load_op(union acpi_operand_object *obj_desc,
                return_ACPI_STATUS(status);
        }
 
-       ACPI_INFO((AE_INFO,
-                  "Dynamic SSDT Load - OemId [%6.6s] OemTableId [%8.8s]",
-                  table_ptr->oem_id, table_ptr->oem_table_id));
-
       cleanup:
        if (ACPI_FAILURE(status)) {
-               ACPI_FREE(table_ptr);
+               acpi_tb_delete_table(&table_desc);
        }
        return_ACPI_STATUS(status);
 }
@@ -477,7 +375,7 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
 {
        acpi_status status = AE_OK;
        union acpi_operand_object *table_desc = ddb_handle;
-       struct acpi_table_desc *table_info;
+       acpi_native_uint table_index;
 
        ACPI_FUNCTION_TRACE(ex_unload_table);
 
@@ -493,19 +391,18 @@ acpi_status acpi_ex_unload_table(union acpi_operand_object *ddb_handle)
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
-       /* Get the actual table descriptor from the ddb_handle */
+       /* Get the table index from the ddb_handle */
 
-       table_info = (struct acpi_table_desc *)table_desc->reference.object;
+       table_index = (acpi_native_uint) table_desc->reference.object;
 
        /*
         * Delete the entire namespace under this table Node
         * (Offset contains the table_id)
         */
-       acpi_ns_delete_namespace_by_owner(table_info->owner_id);
-
-       /* Delete the table itself */
+       acpi_tb_delete_namespace_by_owner(table_index);
+       acpi_tb_release_owner_id(table_index);
 
-       (void)acpi_tb_uninstall_table(table_info->installed_desc);
+       acpi_tb_set_table_loaded_flag(table_index, FALSE);
 
        /* Delete the table descriptor (ddb_handle) */
 
index 544e81a..d470e8b 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 34eec82..7c38528 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -359,8 +359,9 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
        union acpi_operand_object **operand = &walk_state->operands[0];
        union acpi_operand_object *obj_desc;
        struct acpi_namespace_node *node;
-       struct acpi_table_header *table;
        union acpi_operand_object *region_obj2;
+       acpi_native_uint table_index;
+       struct acpi_table_header *table;
 
        ACPI_FUNCTION_TRACE(ex_create_table_region);
 
@@ -380,7 +381,7 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
 
        status = acpi_tb_find_table(operand[1]->string.pointer,
                                    operand[2]->string.pointer,
-                                   operand[3]->string.pointer, &table);
+                                   operand[3]->string.pointer, &table_index);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
@@ -395,6 +396,11 @@ acpi_status acpi_ex_create_table_region(struct acpi_walk_state *walk_state)
        region_obj2 = obj_desc->common.next_object;
        region_obj2->extra.region_context = NULL;
 
+       status = acpi_get_table_by_index(table_index, &table);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
        /* Init the region from the operands */
 
        obj_desc->region.space_id = REGION_DATA_TABLE;
@@ -553,7 +559,8 @@ acpi_ex_create_method(u8 * aml_start,
 
        obj_desc = acpi_ut_create_internal_object(ACPI_TYPE_METHOD);
        if (!obj_desc) {
-               return_ACPI_STATUS(AE_NO_MEMORY);
+               status = AE_NO_MEMORY;
+               goto exit;
        }
 
        /* Save the method's AML pointer and length  */
@@ -576,10 +583,7 @@ acpi_ex_create_method(u8 * aml_start,
         * Get the sync_level. If method is serialized, a mutex will be
         * created for this method when it is parsed.
         */
-       if (acpi_gbl_all_methods_serialized) {
-               obj_desc->method.sync_level = 0;
-               obj_desc->method.method_flags |= AML_METHOD_SERIALIZED;
-       } else if (method_flags & AML_METHOD_SERIALIZED) {
+       if (method_flags & AML_METHOD_SERIALIZED) {
                /*
                 * ACPI 1.0: sync_level = 0
                 * ACPI 2.0: sync_level = sync_level in method declaration
@@ -597,6 +601,7 @@ acpi_ex_create_method(u8 * aml_start,
 
        acpi_ut_remove_reference(obj_desc);
 
+      exit:
        /* Remove a reference to the operand */
 
        acpi_ut_remove_reference(operand[1]);
index 2450943..68d283f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -59,8 +59,6 @@ static void acpi_ex_out_string(char *title, char *value);
 
 static void acpi_ex_out_pointer(char *title, void *value);
 
-static void acpi_ex_out_address(char *title, acpi_physical_address value);
-
 static void
 acpi_ex_dump_object(union acpi_operand_object *obj_desc,
                    struct acpi_exdump_info *info);
@@ -92,10 +90,11 @@ static struct acpi_exdump_info acpi_ex_dump_string[4] = {
        {ACPI_EXD_STRING, 0, NULL}
 };
 
-static struct acpi_exdump_info acpi_ex_dump_buffer[4] = {
+static struct acpi_exdump_info acpi_ex_dump_buffer[5] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_buffer), NULL},
        {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(buffer.length), "Length"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.pointer), "Pointer"},
+       {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(buffer.node), "Parent Node"},
        {ACPI_EXD_BUFFER, 0, NULL}
 };
 
@@ -165,8 +164,8 @@ static struct acpi_exdump_info acpi_ex_dump_power[5] = {
 
 static struct acpi_exdump_info acpi_ex_dump_processor[7] = {
        {ACPI_EXD_INIT, ACPI_EXD_TABLE_SIZE(acpi_ex_dump_processor), NULL},
-       {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"},
-       {ACPI_EXD_UINT32, ACPI_EXD_OFFSET(processor.length), "Length"},
+       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.proc_id), "Processor ID"},
+       {ACPI_EXD_UINT8, ACPI_EXD_OFFSET(processor.length), "Length"},
        {ACPI_EXD_ADDRESS, ACPI_EXD_OFFSET(processor.address), "Address"},
        {ACPI_EXD_POINTER, ACPI_EXD_OFFSET(processor.system_notify),
         "System Notify"},
@@ -379,18 +378,12 @@ acpi_ex_dump_object(union acpi_operand_object *obj_desc,
                        break;
 
                case ACPI_EXD_POINTER:
+               case ACPI_EXD_ADDRESS:
 
                        acpi_ex_out_pointer(name,
                                            *ACPI_CAST_PTR(void *, target));
                        break;
 
-               case ACPI_EXD_ADDRESS:
-
-                       acpi_ex_out_address(name,
-                                           *ACPI_CAST_PTR
-                                           (acpi_physical_address, target));
-                       break;
-
                case ACPI_EXD_STRING:
 
                        acpi_ut_print_string(obj_desc->string.pointer,
@@ -834,16 +827,6 @@ static void acpi_ex_out_pointer(char *title, void *value)
        acpi_os_printf("%20s : %p\n", title, value);
 }
 
-static void acpi_ex_out_address(char *title, acpi_physical_address value)
-{
-
-#if ACPI_MACHINE_WIDTH == 16
-       acpi_os_printf("%20s : %p\n", title, value);
-#else
-       acpi_os_printf("%20s : %8.8X%8.8X\n", title, ACPI_FORMAT_UINT64(value));
-#endif
-}
-
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ex_dump_namespace_node
index 9ea9c3a..2d88a3d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 40f0bee..65a48b6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -257,14 +257,13 @@ acpi_ex_access_region(union acpi_operand_object *obj_desc,
        }
 
        ACPI_DEBUG_PRINT_RAW((ACPI_DB_BFIELD,
-                             " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n",
+                             " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
                              acpi_ut_get_region_name(rgn_desc->region.
                                                      space_id),
                              rgn_desc->region.space_id,
                              obj_desc->common_field.access_byte_width,
                              obj_desc->common_field.base_byte_offset,
-                             field_datum_byte_offset,
-                             ACPI_FORMAT_UINT64(address)));
+                             field_datum_byte_offset, (void *)address));
 
        /* Invoke the appropriate address_space/op_region handler */
 
index bd98aab..f13d1ce 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index bf90f04..5101bad 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -44,6 +44,7 @@
 
 #include <acpi/acpi.h>
 #include <acpi/acinterp.h>
+#include <acpi/acevents.h>
 
 #define _COMPONENT          ACPI_EXECUTER
 ACPI_MODULE_NAME("exmutex")
@@ -150,7 +151,7 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
-       /* Sanity check -- we must have a valid thread ID */
+       /* Sanity check: we must have a valid thread ID */
 
        if (!walk_state->thread) {
                ACPI_ERROR((AE_INFO,
@@ -174,24 +175,28 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
        /* Support for multiple acquires by the owning thread */
 
        if (obj_desc->mutex.owner_thread) {
-
-               /* Special case for Global Lock, allow all threads */
-
-               if ((obj_desc->mutex.owner_thread->thread_id ==
-                    walk_state->thread->thread_id) ||
-                   (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK)) {
+               if (obj_desc->mutex.owner_thread->thread_id ==
+                   walk_state->thread->thread_id) {
                        /*
-                        * The mutex is already owned by this thread,
-                        * just increment the acquisition depth
+                        * The mutex is already owned by this thread, just increment the
+                        * acquisition depth
                         */
                        obj_desc->mutex.acquisition_depth++;
                        return_ACPI_STATUS(AE_OK);
                }
        }
 
-       /* Acquire the mutex, wait if necessary */
+       /* Acquire the mutex, wait if necessary. Special case for Global Lock */
+
+       if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+               status =
+                   acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
+       } else {
+               status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
+                                                  (u16) time_desc->integer.
+                                                  value);
+       }
 
-       status = acpi_ex_system_acquire_mutex(time_desc, obj_desc);
        if (ACPI_FAILURE(status)) {
 
                /* Includes failure from a timeout on time_desc */
@@ -211,7 +216,6 @@ acpi_ex_acquire_mutex(union acpi_operand_object *time_desc,
        /* Link the mutex to the current thread for force-unlock at method exit */
 
        acpi_ex_link_mutex(obj_desc, walk_state->thread);
-
        return_ACPI_STATUS(AE_OK);
 }
 
@@ -232,7 +236,7 @@ acpi_status
 acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
                      struct acpi_walk_state *walk_state)
 {
-       acpi_status status;
+       acpi_status status = AE_OK;
 
        ACPI_FUNCTION_TRACE(ex_release_mutex);
 
@@ -249,7 +253,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
                return_ACPI_STATUS(AE_AML_MUTEX_NOT_ACQUIRED);
        }
 
-       /* Sanity check -- we must have a valid thread ID */
+       /* Sanity check: we must have a valid thread ID */
 
        if (!walk_state->thread) {
                ACPI_ERROR((AE_INFO,
@@ -264,7 +268,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
         */
        if ((obj_desc->mutex.owner_thread->thread_id !=
             walk_state->thread->thread_id)
-           && (obj_desc->mutex.os_mutex != ACPI_GLOBAL_LOCK)) {
+           && (obj_desc->mutex.os_mutex != acpi_gbl_global_lock_mutex)) {
                ACPI_ERROR((AE_INFO,
                            "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX",
                            (unsigned long)walk_state->thread->thread_id,
@@ -274,8 +278,8 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
        }
 
        /*
-        * The sync level of the mutex must be less than or
-        * equal to the current sync level
+        * The sync level of the mutex must be less than or equal to the current
+        * sync level
         */
        if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
                ACPI_ERROR((AE_INFO,
@@ -298,11 +302,15 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
 
        acpi_ex_unlink_mutex(obj_desc);
 
-       /* Release the mutex */
+       /* Release the mutex, special case for Global Lock */
 
-       status = acpi_ex_system_release_mutex(obj_desc);
+       if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+               status = acpi_ev_release_global_lock();
+       } else {
+               acpi_os_release_mutex(obj_desc->mutex.os_mutex);
+       }
 
-       /* Update the mutex and walk state, restore sync_level before acquire */
+       /* Update the mutex and restore sync_level */
 
        obj_desc->mutex.owner_thread = NULL;
        walk_state->thread->current_sync_level =
@@ -321,39 +329,49 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
  *
  * DESCRIPTION: Release all mutexes held by this thread
  *
+ * NOTE: This function is called as the thread is exiting the interpreter.
+ * Mutexes are not released when an individual control method is exited, but
+ * only when the parent thread actually exits the interpreter. This allows one
+ * method to acquire a mutex, and a different method to release it, as long as
+ * this is performed underneath a single parent control method.
+ *
  ******************************************************************************/
 
 void acpi_ex_release_all_mutexes(struct acpi_thread_state *thread)
 {
        union acpi_operand_object *next = thread->acquired_mutex_list;
-       union acpi_operand_object *this;
-       acpi_status status;
+       union acpi_operand_object *obj_desc;
 
        ACPI_FUNCTION_ENTRY();
 
        /* Traverse the list of owned mutexes, releasing each one */
 
        while (next) {
-               this = next;
-               next = this->mutex.next;
+               obj_desc = next;
+               next = obj_desc->mutex.next;
+
+               obj_desc->mutex.prev = NULL;
+               obj_desc->mutex.next = NULL;
+               obj_desc->mutex.acquisition_depth = 0;
+
+               /* Release the mutex, special case for Global Lock */
 
-               this->mutex.acquisition_depth = 1;
-               this->mutex.prev = NULL;
-               this->mutex.next = NULL;
+               if (obj_desc->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
 
-               /* Release the mutex */
+                       /* Ignore errors */
 
-               status = acpi_ex_system_release_mutex(this);
-               if (ACPI_FAILURE(status)) {
-                       continue;
+                       (void)acpi_ev_release_global_lock();
+               } else {
+                       acpi_os_release_mutex(obj_desc->mutex.os_mutex);
                }
 
                /* Mark mutex unowned */
 
-               this->mutex.owner_thread = NULL;
+               obj_desc->mutex.owner_thread = NULL;
 
                /* Update Thread sync_level (Last mutex is the important one) */
 
-               thread->current_sync_level = this->mutex.original_sync_level;
+               thread->current_sync_level =
+                   obj_desc->mutex.original_sync_level;
        }
 }
index d3d7036..1ee4fb1 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6374d8b..252f10a 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -104,9 +104,7 @@ acpi_status acpi_ex_opcode_0A_0T_1R(struct acpi_walk_state *walk_state)
                        status = AE_NO_MEMORY;
                        goto cleanup;
                }
-#if ACPI_MACHINE_WIDTH != 16
                return_desc->integer.value = acpi_os_get_timer();
-#endif
                break;
 
        default:                /*  Unknown opcode  */
index 7d2cbc1..17e652e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e2d945d..7fe67cf 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f0c0ba6..bd80a9c 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 44d064f..a669662 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3cc97ba..2e9ce94 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -155,16 +155,15 @@ acpi_ex_system_memory_space_handler(u32 function,
 
                /* Create a new mapping starting at the address given */
 
-               status = acpi_os_map_memory(address, window_size,
-                                           (void **)&mem_info->
-                                           mapped_logical_address);
-               if (ACPI_FAILURE(status)) {
+               mem_info->mapped_logical_address =
+                   acpi_os_map_memory((acpi_native_uint) address, window_size);
+               if (!mem_info->mapped_logical_address) {
                        ACPI_ERROR((AE_INFO,
                                    "Could not map memory at %8.8X%8.8X, size %X",
                                    ACPI_FORMAT_UINT64(address),
                                    (u32) window_size));
                        mem_info->mapped_length = 0;
-                       return_ACPI_STATUS(status);
+                       return_ACPI_STATUS(AE_NO_MEMORY);
                }
 
                /* Save the physical address and mapping size */
@@ -210,11 +209,10 @@ acpi_ex_system_memory_space_handler(u32 function,
                        *value = (acpi_integer) ACPI_GET32(logical_addr_ptr);
                        break;
 
-#if ACPI_MACHINE_WIDTH != 16
                case 64:
                        *value = (acpi_integer) ACPI_GET64(logical_addr_ptr);
                        break;
-#endif
+
                default:
                        /* bit_width was already validated */
                        break;
@@ -236,11 +234,9 @@ acpi_ex_system_memory_space_handler(u32 function,
                        ACPI_SET32(logical_addr_ptr) = (u32) * value;
                        break;
 
-#if ACPI_MACHINE_WIDTH != 16
                case 64:
                        ACPI_SET64(logical_addr_ptr) = (u64) * value;
                        break;
-#endif
 
                default:
                        /* bit_width was already validated */
index 3089b05..2b3a01c 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6499de8..6c64e55 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -141,7 +141,7 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
        acpi_status status = AE_OK;
        union acpi_operand_object *stack_desc;
        void *temp_node;
-       union acpi_operand_object *obj_desc;
+       union acpi_operand_object *obj_desc = NULL;
        u16 opcode;
 
        ACPI_FUNCTION_TRACE(ex_resolve_object_to_value);
@@ -299,8 +299,6 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
                status = acpi_ds_get_package_arguments(stack_desc);
                break;
 
-               /* These cases may never happen here, but just in case.. */
-
        case ACPI_TYPE_BUFFER_FIELD:
        case ACPI_TYPE_LOCAL_REGION_FIELD:
        case ACPI_TYPE_LOCAL_BANK_FIELD:
@@ -314,6 +312,10 @@ acpi_ex_resolve_object_to_value(union acpi_operand_object **stack_ptr,
                status =
                    acpi_ex_read_data_from_field(walk_state, stack_desc,
                                                 &obj_desc);
+
+               /* Remove a reference to the original operand, then override */
+
+               acpi_ut_remove_reference(*stack_ptr);
                *stack_ptr = (void *)obj_desc;
                break;
 
index 4c93d09..ba76186 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -611,22 +611,20 @@ acpi_ex_resolve_operands(u16 opcode,
                        }
                        goto next_operand;
 
-               case ARGI_REGION_OR_FIELD:
+               case ARGI_REGION_OR_BUFFER:     /* Used by Load() only */
 
-                       /* Need an operand of type REGION or a FIELD in a region */
+                       /* Need an operand of type REGION or a BUFFER (which could be a resolved region field) */
 
                        switch (ACPI_GET_OBJECT_TYPE(obj_desc)) {
+                       case ACPI_TYPE_BUFFER:
                        case ACPI_TYPE_REGION:
-                       case ACPI_TYPE_LOCAL_REGION_FIELD:
-                       case ACPI_TYPE_LOCAL_BANK_FIELD:
-                       case ACPI_TYPE_LOCAL_INDEX_FIELD:
 
                                /* Valid operand */
                                break;
 
                        default:
                                ACPI_ERROR((AE_INFO,
-                                           "Needed [Region/RegionField], found [%s] %p",
+                                           "Needed [Region/Buffer], found [%s] %p",
                                            acpi_ut_get_object_type_name
                                            (obj_desc), obj_desc));
 
index 0456405..f4b69a6 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 591aaf0..1d622c6 100644 (file)
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 99ebe5a..8233d40 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 28aef3e..9460baf 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,6 @@ ACPI_MODULE_NAME("exsystem")
 acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
 {
        acpi_status status;
-       acpi_status status2;
 
        ACPI_FUNCTION_TRACE(ex_system_wait_semaphore);
 
@@ -79,7 +78,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
 
                /* We must wait, so unlock the interpreter */
 
-               acpi_ex_exit_interpreter();
+               acpi_ex_relinquish_interpreter();
 
                status = acpi_os_wait_semaphore(semaphore, 1, timeout);
 
@@ -89,13 +88,7 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
 
                /* Reacquire the interpreter */
 
-               status2 = acpi_ex_enter_interpreter();
-               if (ACPI_FAILURE(status2)) {
-
-                       /* Report fatal error, could not acquire interpreter */
-
-                       return_ACPI_STATUS(status2);
-               }
+               acpi_ex_reacquire_interpreter();
        }
 
        return_ACPI_STATUS(status);
@@ -119,7 +112,6 @@ acpi_status acpi_ex_system_wait_semaphore(acpi_semaphore semaphore, u16 timeout)
 acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
 {
        acpi_status status;
-       acpi_status status2;
 
        ACPI_FUNCTION_TRACE(ex_system_wait_mutex);
 
@@ -132,7 +124,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
 
                /* We must wait, so unlock the interpreter */
 
-               acpi_ex_exit_interpreter();
+               acpi_ex_relinquish_interpreter();
 
                status = acpi_os_acquire_mutex(mutex, timeout);
 
@@ -142,13 +134,7 @@ acpi_status acpi_ex_system_wait_mutex(acpi_mutex mutex, u16 timeout)
 
                /* Reacquire the interpreter */
 
-               status2 = acpi_ex_enter_interpreter();
-               if (ACPI_FAILURE(status2)) {
-
-                       /* Report fatal error, could not acquire interpreter */
-
-                       return_ACPI_STATUS(status2);
-               }
+               acpi_ex_reacquire_interpreter();
        }
 
        return_ACPI_STATUS(status);
@@ -209,96 +195,18 @@ acpi_status acpi_ex_system_do_stall(u32 how_long)
 
 acpi_status acpi_ex_system_do_suspend(acpi_integer how_long)
 {
-       acpi_status status;
-
        ACPI_FUNCTION_ENTRY();
 
        /* Since this thread will sleep, we must release the interpreter */
 
-       acpi_ex_exit_interpreter();
+       acpi_ex_relinquish_interpreter();
 
        acpi_os_sleep(how_long);
 
        /* And now we must get the interpreter again */
 
-       status = acpi_ex_enter_interpreter();
-       return (status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ex_system_acquire_mutex
- *
- * PARAMETERS:  time_desc       - Maximum time to wait for the mutex
- *              obj_desc        - The object descriptor for this op
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Provides an access point to perform synchronization operations
- *              within the AML.  This function will cause a lock to be generated
- *              for the Mutex pointed to by obj_desc.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ex_system_acquire_mutex(union acpi_operand_object * time_desc,
-                            union acpi_operand_object * obj_desc)
-{
-       acpi_status status = AE_OK;
-
-       ACPI_FUNCTION_TRACE_PTR(ex_system_acquire_mutex, obj_desc);
-
-       if (!obj_desc) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
-       /* Support for the _GL_ Mutex object -- go get the global lock */
-
-       if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) {
-               status =
-                   acpi_ev_acquire_global_lock((u16) time_desc->integer.value);
-               return_ACPI_STATUS(status);
-       }
-
-       status = acpi_ex_system_wait_mutex(obj_desc->mutex.os_mutex,
-                                          (u16) time_desc->integer.value);
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ex_system_release_mutex
- *
- * PARAMETERS:  obj_desc        - The object descriptor for this op
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Provides an access point to perform synchronization operations
- *              within the AML.  This operation is a request to release a
- *              previously acquired Mutex.  If the Mutex variable is set then
- *              it will be decremented.
- *
- ******************************************************************************/
-
-acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc)
-{
-       acpi_status status = AE_OK;
-
-       ACPI_FUNCTION_TRACE(ex_system_release_mutex);
-
-       if (!obj_desc) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
-       /* Support for the _GL_ Mutex object -- release the global lock */
-
-       if (obj_desc->mutex.os_mutex == ACPI_GLOBAL_LOCK) {
-               status = acpi_ev_release_global_lock();
-               return_ACPI_STATUS(status);
-       }
-
-       acpi_os_release_mutex(obj_desc->mutex.os_mutex);
-       return_ACPI_STATUS(AE_OK);
+       acpi_ex_reacquire_interpreter();
+       return (AE_OK);
 }
 
 /*******************************************************************************
@@ -314,7 +222,7 @@ acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc)
  *
  ******************************************************************************/
 
-acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc)
+acpi_status acpi_ex_system_signal_event(union acpi_operand_object * obj_desc)
 {
        acpi_status status = AE_OK;
 
index 982c8b6..6b0aecc 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -76,14 +76,15 @@ static u32 acpi_ex_digits_needed(acpi_integer value, u32 base);
  *
  * PARAMETERS:  None
  *
- * RETURN:      Status
+ * RETURN:      None
  *
- * DESCRIPTION: Enter the interpreter execution region.  Failure to enter
- *              the interpreter region is a fatal system error
+ * DESCRIPTION: Enter the interpreter execution region. Failure to enter
+ *              the interpreter region is a fatal system error. Used in
+ *              conjunction with exit_interpreter.
  *
  ******************************************************************************/
 
-acpi_status acpi_ex_enter_interpreter(void)
+void acpi_ex_enter_interpreter(void)
 {
        acpi_status status;
 
@@ -91,31 +92,55 @@ acpi_status acpi_ex_enter_interpreter(void)
 
        status = acpi_ut_acquire_mutex(ACPI_MTX_INTERPRETER);
        if (ACPI_FAILURE(status)) {
-               ACPI_ERROR((AE_INFO, "Could not acquire interpreter mutex"));
+               ACPI_ERROR((AE_INFO,
+                           "Could not acquire AML Interpreter mutex"));
        }
 
-       return_ACPI_STATUS(status);
+       return_VOID;
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_ex_exit_interpreter
+ * FUNCTION:    acpi_ex_reacquire_interpreter
  *
  * PARAMETERS:  None
  *
  * RETURN:      None
  *
- * DESCRIPTION: Exit the interpreter execution region
+ * DESCRIPTION: Reacquire the interpreter execution region from within the
+ *              interpreter code. Failure to enter the interpreter region is a
+ *              fatal system error. Used in  conjuction with
+ *              relinquish_interpreter
+ *
+ ******************************************************************************/
+
+void acpi_ex_reacquire_interpreter(void)
+{
+       ACPI_FUNCTION_TRACE(ex_reacquire_interpreter);
+
+       /*
+        * If the global serialized flag is set, do not release the interpreter,
+        * since it was not actually released by acpi_ex_relinquish_interpreter.
+        * This forces the interpreter to be single threaded.
+        */
+       if (!acpi_gbl_all_methods_serialized) {
+               acpi_ex_enter_interpreter();
+       }
+
+       return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ex_exit_interpreter
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
  *
- * Cases where the interpreter is unlocked:
- *      1) Completion of the execution of a control method
- *      2) Method blocked on a Sleep() AML opcode
- *      3) Method blocked on an Acquire() AML opcode
- *      4) Method blocked on a Wait() AML opcode
- *      5) Method blocked to acquire the global lock
- *      6) Method blocked to execute a serialized control method that is
- *          already executing
- *      7) About to invoke a user-installed opregion handler
+ * DESCRIPTION: Exit the interpreter execution region. This is the top level
+ *              routine used to exit the interpreter when all processing has
+ *              been completed.
  *
  ******************************************************************************/
 
@@ -127,7 +152,46 @@ void acpi_ex_exit_interpreter(void)
 
        status = acpi_ut_release_mutex(ACPI_MTX_INTERPRETER);
        if (ACPI_FAILURE(status)) {
-               ACPI_ERROR((AE_INFO, "Could not release interpreter mutex"));
+               ACPI_ERROR((AE_INFO,
+                           "Could not release AML Interpreter mutex"));
+       }
+
+       return_VOID;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ex_relinquish_interpreter
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Exit the interpreter execution region, from within the
+ *              interpreter - before attempting an operation that will possibly
+ *              block the running thread.
+ *
+ * Cases where the interpreter is unlocked internally
+ *      1) Method to be blocked on a Sleep() AML opcode
+ *      2) Method to be blocked on an Acquire() AML opcode
+ *      3) Method to be blocked on a Wait() AML opcode
+ *      4) Method to be blocked to acquire the global lock
+ *      5) Method to be blocked waiting to execute a serialized control method
+ *          that is currently executing
+ *      6) About to invoke a user-installed opregion handler
+ *
+ ******************************************************************************/
+
+void acpi_ex_relinquish_interpreter(void)
+{
+       ACPI_FUNCTION_TRACE(ex_relinquish_interpreter);
+
+       /*
+        * If the global serialized flag is set, do not release the interpreter.
+        * This forces the interpreter to be single threaded.
+        */
+       if (!acpi_gbl_all_methods_serialized) {
+               acpi_ex_exit_interpreter();
        }
 
        return_VOID;
@@ -141,8 +205,8 @@ void acpi_ex_exit_interpreter(void)
  *
  * RETURN:      none
  *
- * DESCRIPTION: Truncate a number to 32-bits if the currently executing method
- *              belongs to a 32-bit ACPI table.
+ * DESCRIPTION: Truncate an ACPI Integer to 32 bits if the execution mode is
+ *              32-bit, as determined by the revision of the DSDT.
  *
  ******************************************************************************/
 
index f305a82..af22fdf 100644 (file)
@@ -48,8 +48,8 @@ MODULE_LICENSE("GPL");
 
 static int acpi_fan_add(struct acpi_device *device);
 static int acpi_fan_remove(struct acpi_device *device, int type);
-static int acpi_fan_suspend(struct acpi_device *device, int state);
-static int acpi_fan_resume(struct acpi_device *device, int state);
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state);
+static int acpi_fan_resume(struct acpi_device *device);
 
 static struct acpi_driver acpi_fan_driver = {
        .name = ACPI_FAN_DRIVER_NAME,
@@ -237,7 +237,7 @@ static int acpi_fan_remove(struct acpi_device *device, int type)
        return 0;
 }
 
-static int acpi_fan_suspend(struct acpi_device *device, int state)
+static int acpi_fan_suspend(struct acpi_device *device, pm_message_t state)
 {
        if (!device)
                return -EINVAL;
@@ -247,7 +247,7 @@ static int acpi_fan_suspend(struct acpi_device *device, int state)
        return AE_OK;
 }
 
-static int acpi_fan_resume(struct acpi_device *device, int state)
+static int acpi_fan_resume(struct acpi_device *device)
 {
        int result = 0;
        int power_state = 0;
index 8a0324b..7b6c9ff 100644 (file)
@@ -86,129 +86,6 @@ static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
        return ret;
 }
 
-/* Get PCI root bridge's handle from its segment and bus number */
-struct acpi_find_pci_root {
-       unsigned int seg;
-       unsigned int bus;
-       acpi_handle handle;
-};
-
-static acpi_status
-do_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
-{
-       unsigned long *busnr = data;
-       struct acpi_resource_address64 address;
-
-       if (resource->type != ACPI_RESOURCE_TYPE_ADDRESS16 &&
-           resource->type != ACPI_RESOURCE_TYPE_ADDRESS32 &&
-           resource->type != ACPI_RESOURCE_TYPE_ADDRESS64)
-               return AE_OK;
-
-       acpi_resource_to_address64(resource, &address);
-       if ((address.address_length > 0) &&
-           (address.resource_type == ACPI_BUS_NUMBER_RANGE))
-               *busnr = address.minimum;
-
-       return AE_OK;
-}
-
-static int get_root_bridge_busnr(acpi_handle handle)
-{
-       acpi_status status;
-       unsigned long bus, bbn;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
-       acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
-       status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL,
-                                      &bbn);
-       if (status == AE_NOT_FOUND) {
-               /* Assume bus = 0 */
-               printk(KERN_INFO PREFIX
-                      "Assume root bridge [%s] bus is 0\n",
-                      (char *)buffer.pointer);
-               status = AE_OK;
-               bbn = 0;
-       }
-       if (ACPI_FAILURE(status)) {
-               bbn = -ENODEV;
-               goto exit;
-       }
-       if (bbn > 0)
-               goto exit;
-
-       /* _BBN in some systems return 0 for all root bridges */
-       bus = -1;
-       status = acpi_walk_resources(handle, METHOD_NAME__CRS,
-                                    do_root_bridge_busnr_callback, &bus);
-       /* If _CRS failed, we just use _BBN */
-       if (ACPI_FAILURE(status) || (bus == -1))
-               goto exit;
-       /* We select _CRS */
-       if (bbn != bus) {
-               printk(KERN_INFO PREFIX
-                      "_BBN and _CRS returns different value for %s. Select _CRS\n",
-                      (char *)buffer.pointer);
-               bbn = bus;
-       }
-      exit:
-       kfree(buffer.pointer);
-       return (int)bbn;
-}
-
-static acpi_status
-find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv)
-{
-       struct acpi_find_pci_root *find = (struct acpi_find_pci_root *)context;
-       unsigned long seg, bus;
-       acpi_status status;
-       int tmp;
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-
-       acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-
-       status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &seg);
-       if (status == AE_NOT_FOUND) {
-               /* Assume seg = 0 */
-               status = AE_OK;
-               seg = 0;
-       }
-       if (ACPI_FAILURE(status)) {
-               status = AE_CTRL_DEPTH;
-               goto exit;
-       }
-
-       tmp = get_root_bridge_busnr(handle);
-       if (tmp < 0) {
-               printk(KERN_ERR PREFIX
-                      "Find root bridge failed for %s\n",
-                      (char *)buffer.pointer);
-               status = AE_CTRL_DEPTH;
-               goto exit;
-       }
-       bus = tmp;
-
-       if (seg == find->seg && bus == find->bus)
-       {
-               find->handle = handle;
-               status = AE_CTRL_TERMINATE;
-       }
-       else
-               status = AE_OK;
-      exit:
-       kfree(buffer.pointer);
-       return status;
-}
-
-acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
-{
-       struct acpi_find_pci_root find = { seg, bus, NULL };
-
-       acpi_get_devices(PCI_ROOT_HID_STRING, find_pci_rootbridge, &find, NULL);
-       return find.handle;
-}
-EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
-
 /* Get device's handler per its address under its parent */
 struct acpi_find_child {
        acpi_handle handle;
index de50fab..6031ca1 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define _COMPONENT          ACPI_HARDWARE
 ACPI_MODULE_NAME("hwacpi")
 
-/******************************************************************************
- *
- * FUNCTION:    acpi_hw_initialize
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Initialize and validate the various ACPI registers defined in
- *              the FADT.
- *
- ******************************************************************************/
-acpi_status acpi_hw_initialize(void)
-{
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE(hw_initialize);
-
-       /* We must have the ACPI tables by the time we get here */
-
-       if (!acpi_gbl_FADT) {
-               ACPI_ERROR((AE_INFO, "No FADT is present"));
-               return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-       }
-
-       /* Sanity check the FADT for valid values */
-
-       status = acpi_ut_validate_fadt();
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       return_ACPI_STATUS(AE_OK);
-}
-
 /******************************************************************************
  *
  * FUNCTION:    acpi_hw_set_mode
@@ -93,7 +58,6 @@ acpi_status acpi_hw_initialize(void)
  * DESCRIPTION: Transitions the system into the requested mode.
  *
  ******************************************************************************/
-
 acpi_status acpi_hw_set_mode(u32 mode)
 {
 
@@ -106,7 +70,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
         * ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
         * system does not support mode transition.
         */
-       if (!acpi_gbl_FADT->smi_cmd) {
+       if (!acpi_gbl_FADT.smi_command) {
                ACPI_ERROR((AE_INFO,
                            "No SMI_CMD in FADT, mode transition failed"));
                return_ACPI_STATUS(AE_NO_HARDWARE_RESPONSE);
@@ -119,7 +83,7 @@ acpi_status acpi_hw_set_mode(u32 mode)
         * we make sure both the numbers are zero to determine these
         * transitions are not supported.
         */
-       if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) {
+       if (!acpi_gbl_FADT.acpi_enable && !acpi_gbl_FADT.acpi_disable) {
                ACPI_ERROR((AE_INFO,
                            "No ACPI mode transition supported in this system (enable/disable both zero)"));
                return_ACPI_STATUS(AE_OK);
@@ -130,9 +94,8 @@ acpi_status acpi_hw_set_mode(u32 mode)
 
                /* BIOS should have disabled ALL fixed and GP events */
 
-               status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
-                                           (u32) acpi_gbl_FADT->acpi_enable,
-                                           8);
+               status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+                                           (u32) acpi_gbl_FADT.acpi_enable, 8);
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "Attempting to enable ACPI mode\n"));
                break;
@@ -143,8 +106,8 @@ acpi_status acpi_hw_set_mode(u32 mode)
                 * BIOS should clear all fixed status bits and restore fixed event
                 * enable bits to default
                 */
-               status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
-                                           (u32) acpi_gbl_FADT->acpi_disable,
+               status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+                                           (u32) acpi_gbl_FADT.acpi_disable,
                                            8);
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "Attempting to enable Legacy (non-ACPI) mode\n"));
@@ -204,12 +167,11 @@ u32 acpi_hw_get_mode(void)
         * ACPI 2.0 clarified that if SMI_CMD in FADT is zero,
         * system does not support mode transition.
         */
-       if (!acpi_gbl_FADT->smi_cmd) {
+       if (!acpi_gbl_FADT.smi_command) {
                return_UINT32(ACPI_SYS_MODE_ACPI);
        }
 
-       status =
-           acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value, ACPI_MTX_LOCK);
+       status = acpi_get_register(ACPI_BITREG_SCI_ENABLE, &value);
        if (ACPI_FAILURE(status)) {
                return_UINT32(ACPI_SYS_MODE_LEGACY);
        }
index 608a3a6..117a05c 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -105,14 +105,20 @@ acpi_hw_write_gpe_enable_reg(struct acpi_gpe_event_info *gpe_event_info)
 acpi_status acpi_hw_clear_gpe(struct acpi_gpe_event_info * gpe_event_info)
 {
        acpi_status status;
+       u8 register_bit;
 
        ACPI_FUNCTION_ENTRY();
 
+       register_bit = (u8)
+           (1 <<
+            (gpe_event_info->gpe_number -
+             gpe_event_info->register_info->base_gpe_number));
+
        /*
         * Write a one to the appropriate bit in the status register to
         * clear this GPE.
         */
-       status = acpi_hw_low_level_write(8, gpe_event_info->register_bit,
+       status = acpi_hw_low_level_write(8, register_bit,
                                         &gpe_event_info->register_info->
                                         status_address);
 
@@ -155,7 +161,10 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
 
        /* Get the register bitmask for this GPE */
 
-       register_bit = gpe_event_info->register_bit;
+       register_bit = (u8)
+           (1 <<
+            (gpe_event_info->gpe_number -
+             gpe_event_info->register_info->base_gpe_number));
 
        /* GPE currently enabled? (enabled for runtime?) */
 
index fa58c1e..1d371fa 100644 (file)
@@ -7,7 +7,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,17 +54,15 @@ ACPI_MODULE_NAME("hwregs")
  *
  * FUNCTION:    acpi_hw_clear_acpi_status
  *
- * PARAMETERS:  Flags           - Lock the hardware or not
+ * PARAMETERS:  None
  *
- * RETURN:      none
+ * RETURN:      None
  *
  * DESCRIPTION: Clears all fixed and general purpose status bits
  *              THIS FUNCTION MUST BE CALLED WITH INTERRUPTS DISABLED
  *
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
  ******************************************************************************/
-acpi_status acpi_hw_clear_acpi_status(u32 flags)
+acpi_status acpi_hw_clear_acpi_status(void)
 {
        acpi_status status;
        acpi_cpu_flags lock_flags = 0;
@@ -73,7 +71,7 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags)
 
        ACPI_DEBUG_PRINT((ACPI_DB_IO, "About to write %04X to %04X\n",
                          ACPI_BITMASK_ALL_FIXED_STATUS,
-                         (u16) acpi_gbl_FADT->xpm1a_evt_blk.address));
+                         (u16) acpi_gbl_FADT.xpm1a_event_block.address));
 
        lock_flags = acpi_os_acquire_lock(acpi_gbl_hardware_lock);
 
@@ -86,10 +84,10 @@ acpi_status acpi_hw_clear_acpi_status(u32 flags)
 
        /* Clear the fixed events */
 
-       if (acpi_gbl_FADT->xpm1b_evt_blk.address) {
+       if (acpi_gbl_FADT.xpm1b_event_block.address) {
                status =
                    acpi_hw_low_level_write(16, ACPI_BITMASK_ALL_FIXED_STATUS,
-                                           &acpi_gbl_FADT->xpm1b_evt_blk);
+                                           &acpi_gbl_FADT.xpm1b_event_block);
                if (ACPI_FAILURE(status)) {
                        goto unlock_and_exit;
                }
@@ -253,18 +251,15 @@ struct acpi_bit_register_info *acpi_hw_get_bit_register_info(u32 register_id)
  *
  * PARAMETERS:  register_id     - ID of ACPI bit_register to access
  *              return_value    - Value that was read from the register
- *              Flags           - Lock the hardware or not
  *
  * RETURN:      Status and the value read from specified Register. Value
  *              returned is normalized to bit0 (is shifted all the way right)
  *
  * DESCRIPTION: ACPI bit_register read function.
  *
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
  ******************************************************************************/
 
-acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags)
+acpi_status acpi_get_register(u32 register_id, u32 * return_value)
 {
        u32 register_value = 0;
        struct acpi_bit_register_info *bit_reg_info;
@@ -312,16 +307,13 @@ ACPI_EXPORT_SYMBOL(acpi_get_register)
  * PARAMETERS:  register_id     - ID of ACPI bit_register to access
  *              Value           - (only used on write) value to write to the
  *                                Register, NOT pre-normalized to the bit pos
- *              Flags           - Lock the hardware or not
  *
  * RETURN:      Status
  *
  * DESCRIPTION: ACPI Bit Register write function.
  *
- * NOTE: TBD: Flags parameter is obsolete, to be removed
- *
  ******************************************************************************/
-acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
+acpi_status acpi_set_register(u32 register_id, u32 value)
 {
        u32 register_value = 0;
        struct acpi_bit_register_info *bit_reg_info;
@@ -422,8 +414,9 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
                ACPI_DEBUG_PRINT((ACPI_DB_IO,
                                  "PM2 control: Read %X from %8.8X%8.8X\n",
                                  register_value,
-                                 ACPI_FORMAT_UINT64(acpi_gbl_FADT->
-                                                    xpm2_cnt_blk.address)));
+                                 ACPI_FORMAT_UINT64(acpi_gbl_FADT.
+                                                    xpm2_control_block.
+                                                    address)));
 
                ACPI_REGISTER_INSERT_VALUE(register_value,
                                           bit_reg_info->bit_position,
@@ -433,8 +426,9 @@ acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags)
                ACPI_DEBUG_PRINT((ACPI_DB_IO,
                                  "About to write %4.4X to %8.8X%8.8X\n",
                                  register_value,
-                                 ACPI_FORMAT_UINT64(acpi_gbl_FADT->
-                                                    xpm2_cnt_blk.address)));
+                                 ACPI_FORMAT_UINT64(acpi_gbl_FADT.
+                                                    xpm2_control_block.
+                                                    address)));
 
                status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
                                                ACPI_REGISTER_PM2_CONTROL,
@@ -495,7 +489,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
 
                status =
                    acpi_hw_low_level_read(16, &value1,
-                                          &acpi_gbl_FADT->xpm1a_evt_blk);
+                                          &acpi_gbl_FADT.xpm1a_event_block);
                if (ACPI_FAILURE(status)) {
                        goto unlock_and_exit;
                }
@@ -504,7 +498,7 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
 
                status =
                    acpi_hw_low_level_read(16, &value2,
-                                          &acpi_gbl_FADT->xpm1b_evt_blk);
+                                          &acpi_gbl_FADT.xpm1b_event_block);
                value1 |= value2;
                break;
 
@@ -527,14 +521,14 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
 
                status =
                    acpi_hw_low_level_read(16, &value1,
-                                          &acpi_gbl_FADT->xpm1a_cnt_blk);
+                                          &acpi_gbl_FADT.xpm1a_control_block);
                if (ACPI_FAILURE(status)) {
                        goto unlock_and_exit;
                }
 
                status =
                    acpi_hw_low_level_read(16, &value2,
-                                          &acpi_gbl_FADT->xpm1b_cnt_blk);
+                                          &acpi_gbl_FADT.xpm1b_control_block);
                value1 |= value2;
                break;
 
@@ -542,19 +536,20 @@ acpi_hw_register_read(u8 use_lock, u32 register_id, u32 * return_value)
 
                status =
                    acpi_hw_low_level_read(8, &value1,
-                                          &acpi_gbl_FADT->xpm2_cnt_blk);
+                                          &acpi_gbl_FADT.xpm2_control_block);
                break;
 
        case ACPI_REGISTER_PM_TIMER:    /* 32-bit access */
 
                status =
                    acpi_hw_low_level_read(32, &value1,
-                                          &acpi_gbl_FADT->xpm_tmr_blk);
+                                          &acpi_gbl_FADT.xpm_timer_block);
                break;
 
        case ACPI_REGISTER_SMI_COMMAND_BLOCK:   /* 8-bit access */
 
-               status = acpi_os_read_port(acpi_gbl_FADT->smi_cmd, &value1, 8);
+               status =
+                   acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8);
                break;
 
        default:
@@ -635,7 +630,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
 
                status =
                    acpi_hw_low_level_write(16, value,
-                                           &acpi_gbl_FADT->xpm1a_evt_blk);
+                                           &acpi_gbl_FADT.xpm1a_event_block);
                if (ACPI_FAILURE(status)) {
                        goto unlock_and_exit;
                }
@@ -644,7 +639,7 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
 
                status =
                    acpi_hw_low_level_write(16, value,
-                                           &acpi_gbl_FADT->xpm1b_evt_blk);
+                                           &acpi_gbl_FADT.xpm1b_event_block);
                break;
 
        case ACPI_REGISTER_PM1_ENABLE:  /* 16-bit access */
@@ -682,49 +677,50 @@ acpi_status acpi_hw_register_write(u8 use_lock, u32 register_id, u32 value)
 
                status =
                    acpi_hw_low_level_write(16, value,
-                                           &acpi_gbl_FADT->xpm1a_cnt_blk);
+                                           &acpi_gbl_FADT.xpm1a_control_block);
                if (ACPI_FAILURE(status)) {
                        goto unlock_and_exit;
                }
 
                status =
                    acpi_hw_low_level_write(16, value,
-                                           &acpi_gbl_FADT->xpm1b_cnt_blk);
+                                           &acpi_gbl_FADT.xpm1b_control_block);
                break;
 
        case ACPI_REGISTER_PM1A_CONTROL:        /* 16-bit access */
 
                status =
                    acpi_hw_low_level_write(16, value,
-                                           &acpi_gbl_FADT->xpm1a_cnt_blk);
+                                           &acpi_gbl_FADT.xpm1a_control_block);
                break;
 
        case ACPI_REGISTER_PM1B_CONTROL:        /* 16-bit access */
 
                status =
                    acpi_hw_low_level_write(16, value,
-                                           &acpi_gbl_FADT->xpm1b_cnt_blk);
+                                           &acpi_gbl_FADT.xpm1b_control_block);
                break;
 
        case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
 
                status =
                    acpi_hw_low_level_write(8, value,
-                                           &acpi_gbl_FADT->xpm2_cnt_blk);
+                                           &acpi_gbl_FADT.xpm2_control_block);
                break;
 
        case ACPI_REGISTER_PM_TIMER:    /* 32-bit access */
 
                status =
                    acpi_hw_low_level_write(32, value,
-                                           &acpi_gbl_FADT->xpm_tmr_blk);
+                                           &acpi_gbl_FADT.xpm_timer_block);
                break;
 
        case ACPI_REGISTER_SMI_COMMAND_BLOCK:   /* 8-bit access */
 
                /* SMI_CMD is currently always in IO space */
 
-               status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd, value, 8);
+               status =
+                   acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8);
                break;
 
        default:
@@ -783,7 +779,7 @@ acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
         * Two address spaces supported: Memory or IO.
         * PCI_Config is not supported here because the GAS struct is insufficient
         */
-       switch (reg->address_space_id) {
+       switch (reg->space_id) {
        case ACPI_ADR_SPACE_SYSTEM_MEMORY:
 
                status = acpi_os_read_memory((acpi_physical_address) address,
@@ -792,22 +788,20 @@ acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
 
        case ACPI_ADR_SPACE_SYSTEM_IO:
 
-               status = acpi_os_read_port((acpi_io_address) address,
-                                          value, width);
+               status =
+                   acpi_os_read_port((acpi_io_address) address, value, width);
                break;
 
        default:
                ACPI_ERROR((AE_INFO,
-                           "Unsupported address space: %X",
-                           reg->address_space_id));
+                           "Unsupported address space: %X", reg->space_id));
                return (AE_BAD_PARAMETER);
        }
 
        ACPI_DEBUG_PRINT((ACPI_DB_IO,
                          "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
-                         *value, width,
-                         ACPI_FORMAT_UINT64(address),
-                         acpi_ut_get_region_name(reg->address_space_id)));
+                         *value, width, ACPI_FORMAT_UINT64(address),
+                         acpi_ut_get_region_name(reg->space_id)));
 
        return (status);
 }
@@ -854,7 +848,7 @@ acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
         * Two address spaces supported: Memory or IO.
         * PCI_Config is not supported here because the GAS struct is insufficient
         */
-       switch (reg->address_space_id) {
+       switch (reg->space_id) {
        case ACPI_ADR_SPACE_SYSTEM_MEMORY:
 
                status = acpi_os_write_memory((acpi_physical_address) address,
@@ -863,22 +857,20 @@ acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
 
        case ACPI_ADR_SPACE_SYSTEM_IO:
 
-               status = acpi_os_write_port((acpi_io_address) address,
-                                           value, width);
+               status = acpi_os_write_port((acpi_io_address) address, value,
+                                           width);
                break;
 
        default:
                ACPI_ERROR((AE_INFO,
-                           "Unsupported address space: %X",
-                           reg->address_space_id));
+                           "Unsupported address space: %X", reg->space_id));
                return (AE_BAD_PARAMETER);
        }
 
        ACPI_DEBUG_PRINT((ACPI_DB_IO,
                          "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
-                         value, width,
-                         ACPI_FORMAT_UINT64(address),
-                         acpi_ut_get_region_name(reg->address_space_id)));
+                         value, width, ACPI_FORMAT_UINT64(address),
+                         acpi_ut_get_region_name(reg->space_id)));
 
        return (status);
 }
index 8bb43ca..57901ca 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,7 @@
  */
 
 #include <acpi/acpi.h>
+#include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_HARDWARE
 ACPI_MODULE_NAME("hwsleep")
@@ -62,17 +63,32 @@ ACPI_MODULE_NAME("hwsleep")
 acpi_status
 acpi_set_firmware_waking_vector(acpi_physical_address physical_address)
 {
+       struct acpi_table_facs *facs;
+       acpi_status status;
 
        ACPI_FUNCTION_TRACE(acpi_set_firmware_waking_vector);
 
+       /* Get the FACS */
+
+       status =
+           acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+                                   (struct acpi_table_header **)&facs);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
        /* Set the vector */
 
-       if (acpi_gbl_common_fACS.vector_width == 32) {
-               *(ACPI_CAST_PTR
-                 (u32, acpi_gbl_common_fACS.firmware_waking_vector))
-                   = (u32) physical_address;
+       if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
+               /*
+                * ACPI 1.0 FACS or short table or optional X_ field is zero
+                */
+               facs->firmware_waking_vector = (u32) physical_address;
        } else {
-               *acpi_gbl_common_fACS.firmware_waking_vector = physical_address;
+               /*
+                * ACPI 2.0 FACS with valid X_ field
+                */
+               facs->xfirmware_waking_vector = physical_address;
        }
 
        return_ACPI_STATUS(AE_OK);
@@ -97,6 +113,8 @@ ACPI_EXPORT_SYMBOL(acpi_set_firmware_waking_vector)
 acpi_status
 acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
 {
+       struct acpi_table_facs *facs;
+       acpi_status status;
 
        ACPI_FUNCTION_TRACE(acpi_get_firmware_waking_vector);
 
@@ -104,16 +122,29 @@ acpi_get_firmware_waking_vector(acpi_physical_address * physical_address)
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
+       /* Get the FACS */
+
+       status =
+           acpi_get_table_by_index(ACPI_TABLE_INDEX_FACS,
+                                   (struct acpi_table_header **)&facs);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
        /* Get the vector */
 
-       if (acpi_gbl_common_fACS.vector_width == 32) {
-               *physical_address = (acpi_physical_address)
-                   *
-                   (ACPI_CAST_PTR
-                    (u32, acpi_gbl_common_fACS.firmware_waking_vector));
+       if ((facs->length < 32) || (!(facs->xfirmware_waking_vector))) {
+               /*
+                * ACPI 1.0 FACS or short table or optional X_ field is zero
+                */
+               *physical_address =
+                   (acpi_physical_address) facs->firmware_waking_vector;
        } else {
+               /*
+                * ACPI 2.0 FACS with valid X_ field
+                */
                *physical_address =
-                   *acpi_gbl_common_fACS.firmware_waking_vector;
+                   (acpi_physical_address) facs->xfirmware_waking_vector;
        }
 
        return_ACPI_STATUS(AE_OK);
@@ -246,15 +277,14 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
 
        /* Clear wake status */
 
-       status =
-           acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+       status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
 
        /* Clear all fixed and general purpose status bits */
 
-       status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
+       status = acpi_hw_clear_acpi_status();
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
@@ -367,8 +397,7 @@ acpi_status asmlinkage acpi_enter_sleep_state(u8 sleep_state)
        /* Wait until we enter sleep state */
 
        do {
-               status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value,
-                                          ACPI_MTX_DO_NOT_LOCK);
+               status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value);
                if (ACPI_FAILURE(status)) {
                        return_ACPI_STATUS(status);
                }
@@ -401,13 +430,12 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
 
        ACPI_FUNCTION_TRACE(acpi_enter_sleep_state_s4bios);
 
-       status =
-           acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
+       status = acpi_set_register(ACPI_BITREG_WAKE_STATUS, 1);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
 
-       status = acpi_hw_clear_acpi_status(ACPI_MTX_DO_NOT_LOCK);
+       status = acpi_hw_clear_acpi_status();
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
@@ -429,13 +457,12 @@ acpi_status asmlinkage acpi_enter_sleep_state_s4bios(void)
 
        ACPI_FLUSH_CPU_CACHE();
 
-       status = acpi_os_write_port(acpi_gbl_FADT->smi_cmd,
-                                   (u32) acpi_gbl_FADT->S4bios_req, 8);
+       status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+                                   (u32) acpi_gbl_FADT.S4bios_request, 8);
 
        do {
                acpi_os_stall(1000);
-               status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value,
-                                          ACPI_MTX_DO_NOT_LOCK);
+               status = acpi_get_register(ACPI_BITREG_WAKE_STATUS, &in_value);
                if (ACPI_FAILURE(status)) {
                        return_ACPI_STATUS(status);
                }
@@ -568,13 +595,11 @@ acpi_status acpi_leave_sleep_state(u8 sleep_state)
 
        (void)
            acpi_set_register(acpi_gbl_fixed_event_info
-                             [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1,
-                             ACPI_MTX_DO_NOT_LOCK);
+                             [ACPI_EVENT_POWER_BUTTON].enable_register_id, 1);
 
        (void)
            acpi_set_register(acpi_gbl_fixed_event_info
-                             [ACPI_EVENT_POWER_BUTTON].status_register_id, 1,
-                             ACPI_MTX_DO_NOT_LOCK);
+                             [ACPI_EVENT_POWER_BUTTON].status_register_id, 1);
 
        arg.integer.value = ACPI_SST_WORKING;
        status = acpi_evaluate_object(NULL, METHOD_NAME__SST, &arg_list, NULL);
index c4ec47c..c32eab6 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -66,7 +66,7 @@ acpi_status acpi_get_timer_resolution(u32 * resolution)
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
-       if (acpi_gbl_FADT->tmr_val_ext == 0) {
+       if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) {
                *resolution = 24;
        } else {
                *resolution = 32;
@@ -98,7 +98,8 @@ acpi_status acpi_get_timer(u32 * ticks)
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
-       status = acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT->xpm_tmr_blk);
+       status =
+           acpi_hw_low_level_read(32, ticks, &acpi_gbl_FADT.xpm_timer_block);
 
        return_ACPI_STATUS(status);
 }
@@ -153,7 +154,7 @@ acpi_get_timer_duration(u32 start_ticks, u32 end_ticks, u32 * time_elapsed)
        if (start_ticks < end_ticks) {
                delta_ticks = end_ticks - start_ticks;
        } else if (start_ticks > end_ticks) {
-               if (acpi_gbl_FADT->tmr_val_ext == 0) {
+               if ((acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) == 0) {
 
                        /* 24-bit Timer */
 
diff --git a/drivers/acpi/motherboard.c b/drivers/acpi/motherboard.c
deleted file mode 100644 (file)
index 2e17ec7..0000000
+++ /dev/null
@@ -1,191 +0,0 @@
-/* 
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *  This program is free software; 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.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-/* Purpose: Prevent PCMCIA cards from using motherboard resources. */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/pci.h>
-#include <linux/ioport.h>
-#include <asm/io.h>
-
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
-
-#define _COMPONENT             ACPI_SYSTEM_COMPONENT
-ACPI_MODULE_NAME("acpi_motherboard")
-
-/* Dell use PNP0C01 instead of PNP0C02 */
-#define ACPI_MB_HID1                   "PNP0C01"
-#define ACPI_MB_HID2                   "PNP0C02"
-/**
- * Doesn't care about legacy IO ports, only IO ports beyond 0x1000 are reserved
- * Doesn't care about the failure of 'request_region', since other may reserve
- * the io ports as well
- */
-#define IS_RESERVED_ADDR(base, len) \
-       (((len) > 0) && ((base) > 0) && ((base) + (len) < IO_SPACE_LIMIT) \
-       && ((base) + (len) > PCIBIOS_MIN_IO))
-/*
- * Clearing the flag (IORESOURCE_BUSY) allows drivers to use
- * the io ports if they really know they can use it, while
- * still preventing hotplug PCI devices from using it.
- */
-
-/*
- * When CONFIG_PNP is enabled, pnp/system.c binds to PNP0C01
- * and PNP0C02, redundant with acpi_reserve_io_ranges().
- * But acpi_reserve_io_ranges() is necessary for !CONFIG_PNP.
- */
-static acpi_status acpi_reserve_io_ranges(struct acpi_resource *res, void *data)
-{
-       struct resource *requested_res = NULL;
-
-
-       if (res->type == ACPI_RESOURCE_TYPE_IO) {
-               struct acpi_resource_io *io_res = &res->data.io;
-
-               if (io_res->minimum != io_res->maximum)
-                       return AE_OK;
-               if (IS_RESERVED_ADDR
-                   (io_res->minimum, io_res->address_length)) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                         "Motherboard resources 0x%08x - 0x%08x\n",
-                                         io_res->minimum,
-                                         io_res->minimum +
-                                         io_res->address_length));
-                       requested_res =
-                           request_region(io_res->minimum,
-                                          io_res->address_length, "motherboard");
-               }
-       } else if (res->type == ACPI_RESOURCE_TYPE_FIXED_IO) {
-               struct acpi_resource_fixed_io *fixed_io_res =
-                   &res->data.fixed_io;
-
-               if (IS_RESERVED_ADDR
-                   (fixed_io_res->address, fixed_io_res->address_length)) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                         "Motherboard resources 0x%08x - 0x%08x\n",
-                                         fixed_io_res->address,
-                                         fixed_io_res->address +
-                                         fixed_io_res->address_length));
-                       requested_res =
-                           request_region(fixed_io_res->address,
-                                          fixed_io_res->address_length,
-                                          "motherboard");
-               }
-       } else {
-               /* Memory mapped IO? */
-       }
-
-       if (requested_res)
-               requested_res->flags &= ~IORESOURCE_BUSY;
-       return AE_OK;
-}
-
-static int acpi_motherboard_add(struct acpi_device *device)
-{
-       if (!device)
-               return -EINVAL;
-       acpi_walk_resources(device->handle, METHOD_NAME__CRS,
-                           acpi_reserve_io_ranges, NULL);
-
-       return 0;
-}
-
-static struct acpi_driver acpi_motherboard_driver1 = {
-       .name = "motherboard",
-       .class = "",
-       .ids = ACPI_MB_HID1,
-       .ops = {
-               .add = acpi_motherboard_add,
-               },
-};
-
-static struct acpi_driver acpi_motherboard_driver2 = {
-       .name = "motherboard",
-       .class = "",
-       .ids = ACPI_MB_HID2,
-       .ops = {
-               .add = acpi_motherboard_add,
-               },
-};
-
-static void __init acpi_request_region (struct acpi_generic_address *addr,
-       unsigned int length, char *desc)
-{
-       if (!addr->address || !length)
-               return;
-
-       if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_IO)
-               request_region(addr->address, length, desc);
-       else if (addr->address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
-               request_mem_region(addr->address, length, desc);
-}
-
-static void __init acpi_reserve_resources(void)
-{
-       acpi_request_region(&acpi_gbl_FADT->xpm1a_evt_blk,
-                              acpi_gbl_FADT->pm1_evt_len, "ACPI PM1a_EVT_BLK");
-
-       acpi_request_region(&acpi_gbl_FADT->xpm1b_evt_blk,
-                              acpi_gbl_FADT->pm1_evt_len, "ACPI PM1b_EVT_BLK");
-
-       acpi_request_region(&acpi_gbl_FADT->xpm1a_cnt_blk,
-                              acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1a_CNT_BLK");
-
-       acpi_request_region(&acpi_gbl_FADT->xpm1b_cnt_blk,
-                              acpi_gbl_FADT->pm1_cnt_len, "ACPI PM1b_CNT_BLK");
-
-       if (acpi_gbl_FADT->pm_tm_len == 4)
-               acpi_request_region(&acpi_gbl_FADT->xpm_tmr_blk, 4, "ACPI PM_TMR");
-
-       acpi_request_region(&acpi_gbl_FADT->xpm2_cnt_blk,
-                              acpi_gbl_FADT->pm2_cnt_len, "ACPI PM2_CNT_BLK");
-
-       /* Length of GPE blocks must be a non-negative multiple of 2 */
-
-       if (!(acpi_gbl_FADT->gpe0_blk_len & 0x1))
-               acpi_request_region(&acpi_gbl_FADT->xgpe0_blk,
-                              acpi_gbl_FADT->gpe0_blk_len, "ACPI GPE0_BLK");
-
-       if (!(acpi_gbl_FADT->gpe1_blk_len & 0x1))
-               acpi_request_region(&acpi_gbl_FADT->xgpe1_blk,
-                              acpi_gbl_FADT->gpe1_blk_len, "ACPI GPE1_BLK");
-}
-
-static int __init acpi_motherboard_init(void)
-{
-       acpi_bus_register_driver(&acpi_motherboard_driver1);
-       acpi_bus_register_driver(&acpi_motherboard_driver2);
-       /*
-        * Guarantee motherboard IO reservation first
-        * This module must run after scan.c
-        */
-       if (!acpi_disabled)
-               acpi_reserve_resources();
-       return 0;
-}
-
-/**
- * Reserve motherboard resources after PCI claim BARs,
- * but before PCI assign resources for uninitialized PCI devices
- */
-fs_initcall(acpi_motherboard_init);
index c1c6c23..57faf59 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -195,31 +195,27 @@ acpi_status acpi_ns_root_initialize(void)
                                obj_desc->mutex.sync_level =
                                    (u8) (ACPI_TO_INTEGER(val) - 1);
 
-                               if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
+                               /* Create a mutex */
 
-                                       /* Create a counting semaphore for the global lock */
+                               status =
+                                   acpi_os_create_mutex(&obj_desc->mutex.
+                                                        os_mutex);
+                               if (ACPI_FAILURE(status)) {
+                                       acpi_ut_remove_reference(obj_desc);
+                                       goto unlock_and_exit;
+                               }
 
-                                       status =
-                                           acpi_os_create_semaphore
-                                           (ACPI_NO_UNIT_LIMIT, 1,
-                                            &acpi_gbl_global_lock_semaphore);
-                                       if (ACPI_FAILURE(status)) {
-                                               acpi_ut_remove_reference
-                                                   (obj_desc);
-                                               goto unlock_and_exit;
-                                       }
+                               /* Special case for ACPI Global Lock */
 
-                                       /* Mark this mutex as very special */
+                               if (ACPI_STRCMP(init_val->name, "_GL_") == 0) {
+                                       acpi_gbl_global_lock_mutex =
+                                           obj_desc->mutex.os_mutex;
 
-                                       obj_desc->mutex.os_mutex =
-                                           ACPI_GLOBAL_LOCK;
-                               } else {
-                                       /* Create a mutex */
+                                       /* Create additional counting semaphore for global lock */
 
                                        status =
-                                           acpi_os_create_mutex(&obj_desc->
-                                                                mutex.
-                                                                os_mutex);
+                                           acpi_os_create_semaphore(1, 0,
+                                                                    &acpi_gbl_global_lock_semaphore);
                                        if (ACPI_FAILURE(status)) {
                                                acpi_ut_remove_reference
                                                    (obj_desc);
index 55b407a..1d693d8 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -61,6 +61,9 @@ ACPI_MODULE_NAME("nsalloc")
 struct acpi_namespace_node *acpi_ns_create_node(u32 name)
 {
        struct acpi_namespace_node *node;
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+       u32 temp;
+#endif
 
        ACPI_FUNCTION_TRACE(ns_create_node);
 
@@ -71,6 +74,15 @@ struct acpi_namespace_node *acpi_ns_create_node(u32 name)
 
        ACPI_MEM_TRACKING(acpi_gbl_ns_node_list->total_allocated++);
 
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+       temp =
+           acpi_gbl_ns_node_list->total_allocated -
+           acpi_gbl_ns_node_list->total_freed;
+       if (temp > acpi_gbl_ns_node_list->max_occupied) {
+               acpi_gbl_ns_node_list->max_occupied = temp;
+       }
+#endif
+
        node->name.integer = name;
        ACPI_SET_DESCRIPTOR_TYPE(node, ACPI_DESC_TYPE_NAMED);
        return_PTR(node);
index d72df66..1fc4f86 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -205,7 +205,7 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
 
                if (!acpi_ut_valid_acpi_name(this_node->name.integer)) {
                        this_node->name.integer =
-                           acpi_ut_repair_name(this_node->name.integer);
+                           acpi_ut_repair_name(this_node->name.ascii);
 
                        ACPI_WARNING((AE_INFO, "Invalid ACPI Name %08X",
                                      this_node->name.integer));
@@ -226,6 +226,12 @@ acpi_ns_dump_one_object(acpi_handle obj_handle,
        obj_desc = acpi_ns_get_attached_object(this_node);
        acpi_dbg_level = dbg_level;
 
+       /* Temp nodes are those nodes created by a control method */
+
+       if (this_node->flags & ANOBJ_TEMPORARY) {
+               acpi_os_printf("(T) ");
+       }
+
        switch (info->display_type & ACPI_DISPLAY_MASK) {
        case ACPI_DISPLAY_SUMMARY:
 
@@ -623,7 +629,8 @@ acpi_ns_dump_objects(acpi_object_type type,
        info.display_type = display_type;
 
        (void)acpi_ns_walk_namespace(type, start_handle, max_depth,
-                                    ACPI_NS_WALK_NO_UNLOCK,
+                                    ACPI_NS_WALK_NO_UNLOCK |
+                                    ACPI_NS_WALK_TEMP_NODES,
                                     acpi_ns_dump_one_object, (void *)&info,
                                     NULL);
 }
index c6bf5d3..5097e16 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4b0a4a8..aa6370c 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -154,11 +154,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
                 * Execute the method via the interpreter. The interpreter is locked
                 * here before calling into the AML parser
                 */
-               status = acpi_ex_enter_interpreter();
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
-               }
-
+               acpi_ex_enter_interpreter();
                status = acpi_ps_execute_method(info);
                acpi_ex_exit_interpreter();
        } else {
@@ -182,10 +178,7 @@ acpi_status acpi_ns_evaluate(struct acpi_evaluate_info *info)
                 * resolution, we must lock it because we could access an opregion.
                 * The opregion access code assumes that the interpreter is locked.
                 */
-               status = acpi_ex_enter_interpreter();
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
-               }
+               acpi_ex_enter_interpreter();
 
                /* Function has a strange interface */
 
index aec8488..326af8f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -213,7 +213,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
                        u32 level, void *context, void **return_value)
 {
        acpi_object_type type;
-       acpi_status status;
+       acpi_status status = AE_OK;
        struct acpi_init_walk_info *info =
            (struct acpi_init_walk_info *)context;
        struct acpi_namespace_node *node =
@@ -267,10 +267,7 @@ acpi_ns_init_one_object(acpi_handle obj_handle,
        /*
         * Must lock the interpreter before executing AML code
         */
-       status = acpi_ex_enter_interpreter();
-       if (ACPI_FAILURE(status)) {
-               return (status);
-       }
+       acpi_ex_enter_interpreter();
 
        /*
         * Each of these types can contain executable AML code within the
index fe75d88..d4f9654 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
 #include <acpi/acdispat.h>
+#include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsload")
 
 /* Local prototypes */
-static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type);
-
 #ifdef ACPI_FUTURE_IMPLEMENTATION
 acpi_status acpi_ns_unload_namespace(acpi_handle handle);
 
@@ -62,7 +61,7 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
  *
  * FUNCTION:    acpi_ns_load_table
  *
- * PARAMETERS:  table_desc      - Descriptor for table to be loaded
+ * PARAMETERS:  table_index     - Index for table to be loaded
  *              Node            - Owning NS node
  *
  * RETURN:      Status
@@ -72,42 +71,13 @@ static acpi_status acpi_ns_delete_subtree(acpi_handle start_handle);
  ******************************************************************************/
 
 acpi_status
-acpi_ns_load_table(struct acpi_table_desc *table_desc,
+acpi_ns_load_table(acpi_native_uint table_index,
                   struct acpi_namespace_node *node)
 {
        acpi_status status;
 
        ACPI_FUNCTION_TRACE(ns_load_table);
 
-       /* Check if table contains valid AML (must be DSDT, PSDT, SSDT, etc.) */
-
-       if (!
-           (acpi_gbl_table_data[table_desc->type].
-            flags & ACPI_TABLE_EXECUTABLE)) {
-
-               /* Just ignore this table */
-
-               return_ACPI_STATUS(AE_OK);
-       }
-
-       /* Check validity of the AML start and length */
-
-       if (!table_desc->aml_start) {
-               ACPI_ERROR((AE_INFO, "Null AML pointer"));
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "AML block at %p\n",
-                         table_desc->aml_start));
-
-       /* Ignore table if there is no AML contained within */
-
-       if (!table_desc->aml_length) {
-               ACPI_WARNING((AE_INFO, "Zero-length AML block in table [%4.4s]",
-                             table_desc->pointer->signature));
-               return_ACPI_STATUS(AE_OK);
-       }
-
        /*
         * Parse the table and load the namespace with all named
         * objects found within.  Control methods are NOT parsed
@@ -117,15 +87,34 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc,
         * to another control method, we can't continue parsing
         * because we don't know how many arguments to parse next!
         */
+       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
+       /* If table already loaded into namespace, just return */
+
+       if (acpi_tb_is_table_loaded(table_index)) {
+               status = AE_ALREADY_EXISTS;
+               goto unlock;
+       }
+
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                          "**** Loading table into namespace ****\n"));
 
-       status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
+       status = acpi_tb_allocate_owner_id(table_index);
        if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
+               goto unlock;
+       }
+
+       status = acpi_ns_parse_table(table_index, node->child);
+       if (ACPI_SUCCESS(status)) {
+               acpi_tb_set_table_loaded_flag(table_index, TRUE);
+       } else {
+               acpi_tb_release_owner_id(table_index);
        }
 
-       status = acpi_ns_parse_table(table_desc, node->child);
+      unlock:
        (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
 
        if (ACPI_FAILURE(status)) {
@@ -141,7 +130,7 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc,
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                          "**** Begin Table Method Parsing and Object Initialization ****\n"));
 
-       status = acpi_ds_initialize_objects(table_desc, node);
+       status = acpi_ds_initialize_objects(table_index, node);
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                          "**** Completed Table Method Parsing and Object Initialization ****\n"));
@@ -149,99 +138,7 @@ acpi_ns_load_table(struct acpi_table_desc *table_desc,
        return_ACPI_STATUS(status);
 }
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ns_load_table_by_type
- *
- * PARAMETERS:  table_type          - Id of the table type to load
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Load an ACPI table or tables into the namespace.  All tables
- *              of the given type are loaded.  The mechanism allows this
- *              routine to be called repeatedly.
- *
- ******************************************************************************/
-
-static acpi_status acpi_ns_load_table_by_type(acpi_table_type table_type)
-{
-       u32 i;
-       acpi_status status;
-       struct acpi_table_desc *table_desc;
-
-       ACPI_FUNCTION_TRACE(ns_load_table_by_type);
-
-       status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /*
-        * Table types supported are:
-        * DSDT (one), SSDT/PSDT (multiple)
-        */
-       switch (table_type) {
-       case ACPI_TABLE_ID_DSDT:
-
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace load: DSDT\n"));
-
-               table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_DSDT].next;
-
-               /* If table already loaded into namespace, just return */
-
-               if (table_desc->loaded_into_namespace) {
-                       goto unlock_and_exit;
-               }
-
-               /* Now load the single DSDT */
-
-               status = acpi_ns_load_table(table_desc, acpi_gbl_root_node);
-               if (ACPI_SUCCESS(status)) {
-                       table_desc->loaded_into_namespace = TRUE;
-               }
-               break;
-
-       case ACPI_TABLE_ID_SSDT:
-       case ACPI_TABLE_ID_PSDT:
-
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Namespace load: %d SSDT or PSDTs\n",
-                                 acpi_gbl_table_lists[table_type].count));
-
-               /*
-                * Traverse list of SSDT or PSDT tables
-                */
-               table_desc = acpi_gbl_table_lists[table_type].next;
-               for (i = 0; i < acpi_gbl_table_lists[table_type].count; i++) {
-                       /*
-                        * Only attempt to load table into namespace if it is not
-                        * already loaded!
-                        */
-                       if (!table_desc->loaded_into_namespace) {
-                               status =
-                                   acpi_ns_load_table(table_desc,
-                                                      acpi_gbl_root_node);
-                               if (ACPI_FAILURE(status)) {
-                                       break;
-                               }
-
-                               table_desc->loaded_into_namespace = TRUE;
-                       }
-
-                       table_desc = table_desc->next;
-               }
-               break;
-
-       default:
-               status = AE_SUPPORT;
-               break;
-       }
-
-      unlock_and_exit:
-       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-       return_ACPI_STATUS(status);
-}
-
+#ifdef ACPI_OBSOLETE_FUNCTIONS
 /*******************************************************************************
  *
  * FUNCTION:    acpi_load_namespace
@@ -288,6 +185,7 @@ acpi_status acpi_ns_load_namespace(void)
 
        return_ACPI_STATUS(status);
 }
+#endif
 
 #ifdef ACPI_FUTURE_IMPLEMENTATION
 /*******************************************************************************
index 97b8332..cbd94af 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index aabe879..d9d7377 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 155505a..e696aa8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -45,6 +45,7 @@
 #include <acpi/acnamesp.h>
 #include <acpi/acparser.h>
 #include <acpi/acdispat.h>
+#include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_NAMESPACE
 ACPI_MODULE_NAME("nsparse")
@@ -62,14 +63,24 @@ ACPI_MODULE_NAME("nsparse")
  *
  ******************************************************************************/
 acpi_status
-acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
+acpi_ns_one_complete_parse(acpi_native_uint pass_number,
+                          acpi_native_uint table_index)
 {
        union acpi_parse_object *parse_root;
        acpi_status status;
+       acpi_native_uint aml_length;
+       u8 *aml_start;
        struct acpi_walk_state *walk_state;
+       struct acpi_table_header *table;
+       acpi_owner_id owner_id;
 
        ACPI_FUNCTION_TRACE(ns_one_complete_parse);
 
+       status = acpi_tb_get_owner_id(table_index, &owner_id);
+       if (ACPI_FAILURE(status)) {
+               return_ACPI_STATUS(status);
+       }
+
        /* Create and init a Root Node */
 
        parse_root = acpi_ps_create_scope_op();
@@ -79,26 +90,41 @@ acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
 
        /* Create and initialize a new walk state */
 
-       walk_state = acpi_ds_create_walk_state(table_desc->owner_id,
-                                              NULL, NULL, NULL);
+       walk_state = acpi_ds_create_walk_state(owner_id, NULL, NULL, NULL);
        if (!walk_state) {
                acpi_ps_free_op(parse_root);
                return_ACPI_STATUS(AE_NO_MEMORY);
        }
 
-       status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
-                                      table_desc->aml_start,
-                                      table_desc->aml_length, NULL,
-                                      pass_number);
+       status = acpi_get_table_by_index(table_index, &table);
+       if (ACPI_FAILURE(status)) {
+               acpi_ds_delete_walk_state(walk_state);
+               acpi_ps_free_op(parse_root);
+               return_ACPI_STATUS(status);
+       }
+
+       /* Table must consist of at least a complete header */
+
+       if (table->length < sizeof(struct acpi_table_header)) {
+               status = AE_BAD_HEADER;
+       } else {
+               aml_start = (u8 *) table + sizeof(struct acpi_table_header);
+               aml_length = table->length - sizeof(struct acpi_table_header);
+               status = acpi_ds_init_aml_walk(walk_state, parse_root, NULL,
+                                              aml_start, aml_length, NULL,
+                                              (u8) pass_number);
+       }
+
        if (ACPI_FAILURE(status)) {
                acpi_ds_delete_walk_state(walk_state);
+               acpi_ps_delete_parse_tree(parse_root);
                return_ACPI_STATUS(status);
        }
 
        /* Parse the AML */
 
        ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "*PARSE* pass %d parse\n",
-                         pass_number));
+                         (unsigned)pass_number));
        status = acpi_ps_parse_aml(walk_state);
 
        acpi_ps_delete_parse_tree(parse_root);
@@ -119,7 +145,7 @@ acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc)
  ******************************************************************************/
 
 acpi_status
-acpi_ns_parse_table(struct acpi_table_desc *table_desc,
+acpi_ns_parse_table(acpi_native_uint table_index,
                    struct acpi_namespace_node *start_node)
 {
        acpi_status status;
@@ -134,10 +160,10 @@ acpi_ns_parse_table(struct acpi_table_desc *table_desc,
         * each Parser Op subtree is deleted when it is finished.  This saves
         * a great deal of memory, and allows a small cache of parse objects
         * to service the entire parse.  The second pass of the parse then
-        * performs another complete parse of the AML..
+        * performs another complete parse of the AML.
         */
        ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 1\n"));
-       status = acpi_ns_one_complete_parse(1, table_desc);
+       status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS1, table_index);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
@@ -152,7 +178,7 @@ acpi_ns_parse_table(struct acpi_table_desc *table_desc,
         * parse objects are all cached.
         */
        ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "**** Start pass 2\n"));
-       status = acpi_ns_one_complete_parse(2, table_desc);
+       status = acpi_ns_one_complete_parse(ACPI_IMODE_LOAD_PASS2, table_index);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
index 500e2bb..e863be6 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -321,7 +321,8 @@ acpi_ns_search_and_enter(u32 target_name,
         * even though there are a few bad names.
         */
        if (!acpi_ut_valid_acpi_name(target_name)) {
-               target_name = acpi_ut_repair_name(target_name);
+               target_name =
+                   acpi_ut_repair_name(ACPI_CAST_PTR(char, &target_name));
 
                /* Report warning only if in strict mode or debug mode */
 
@@ -401,6 +402,10 @@ acpi_ns_search_and_enter(u32 target_name,
        }
 #endif
 
+       if (flags & ACPI_NS_TEMPORARY) {
+               new_node->flags |= ANOBJ_TEMPORARY;
+       }
+
        /* Install the new object into the parent's list of children */
 
        acpi_ns_install_node(walk_state, node, new_node, type);
index aa4e799..90fd059 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -770,13 +770,6 @@ void acpi_ns_terminate(void)
        }
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Namespace freed\n"));
-
-       /*
-        * 2) Now we can delete the ACPI tables
-        */
-       acpi_tb_delete_all_tables();
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
-
        return_VOID;
 }
 
index c8f6bef..94eb8f3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -126,7 +126,7 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type,
  * PARAMETERS:  Type                - acpi_object_type to search for
  *              start_node          - Handle in namespace where search begins
  *              max_depth           - Depth to which search is to reach
- *              unlock_before_callback- Whether to unlock the NS before invoking
+ *              Flags               - Whether to unlock the NS before invoking
  *                                    the callback routine
  *              user_function       - Called when an object of "Type" is found
  *              Context             - Passed to user function
@@ -153,7 +153,7 @@ acpi_status
 acpi_ns_walk_namespace(acpi_object_type type,
                       acpi_handle start_node,
                       u32 max_depth,
-                      u8 unlock_before_callback,
+                      u32 flags,
                       acpi_walk_callback user_function,
                       void *context, void **return_value)
 {
@@ -193,20 +193,34 @@ acpi_ns_walk_namespace(acpi_object_type type,
                    acpi_ns_get_next_node(ACPI_TYPE_ANY, parent_node,
                                          child_node);
                if (child_node) {
-                       /*
-                        * Found node, Get the type if we are not
-                        * searching for ANY
-                        */
+
+                       /* Found next child, get the type if we are not searching for ANY */
+
                        if (type != ACPI_TYPE_ANY) {
                                child_type = child_node->type;
                        }
 
-                       if (child_type == type) {
+                       /*
+                        * Ignore all temporary namespace nodes (created during control
+                        * method execution) unless told otherwise. These temporary nodes
+                        * can cause a race condition because they can be deleted during the
+                        * execution of the user function (if the namespace is unlocked before
+                        * invocation of the user function.) Only the debugger namespace dump
+                        * will examine the temporary nodes.
+                        */
+                       if ((child_node->flags & ANOBJ_TEMPORARY) &&
+                           !(flags & ACPI_NS_WALK_TEMP_NODES)) {
+                               status = AE_CTRL_DEPTH;
+                       }
+
+                       /* Type must match requested type */
+
+                       else if (child_type == type) {
                                /*
-                                * Found a matching node, invoke the user
-                                * callback function
+                                * Found a matching node, invoke the user callback function.
+                                * Unlock the namespace if flag is set.
                                 */
-                               if (unlock_before_callback) {
+                               if (flags & ACPI_NS_WALK_UNLOCK) {
                                        mutex_status =
                                            acpi_ut_release_mutex
                                            (ACPI_MTX_NAMESPACE);
@@ -216,10 +230,11 @@ acpi_ns_walk_namespace(acpi_object_type type,
                                        }
                                }
 
-                               status = user_function(child_node, level,
-                                                      context, return_value);
+                               status =
+                                   user_function(child_node, level, context,
+                                                 return_value);
 
-                               if (unlock_before_callback) {
+                               if (flags & ACPI_NS_WALK_UNLOCK) {
                                        mutex_status =
                                            acpi_ut_acquire_mutex
                                            (ACPI_MTX_NAMESPACE);
@@ -251,20 +266,17 @@ acpi_ns_walk_namespace(acpi_object_type type,
                        }
 
                        /*
-                        * Depth first search:
-                        * Attempt to go down another level in the namespace
-                        * if we are allowed to.  Don't go any further if we
-                        * have reached the caller specified maximum depth
-                        * or if the user function has specified that the
-                        * maximum depth has been reached.
+                        * Depth first search: Attempt to go down another level in the
+                        * namespace if we are allowed to.  Don't go any further if we have
+                        * reached the caller specified maximum depth or if the user
+                        * function has specified that the maximum depth has been reached.
                         */
                        if ((level < max_depth) && (status != AE_CTRL_DEPTH)) {
                                if (acpi_ns_get_next_node
                                    (ACPI_TYPE_ANY, child_node, NULL)) {
-                                       /*
-                                        * There is at least one child of this
-                                        * node, visit the onde
-                                        */
+
+                                       /* There is at least one child of this node, visit it */
+
                                        level++;
                                        parent_node = child_node;
                                        child_node = NULL;
@@ -272,9 +284,8 @@ acpi_ns_walk_namespace(acpi_object_type type,
                        }
                } else {
                        /*
-                        * No more children of this node (acpi_ns_get_next_node
-                        * failed), go back upwards in the namespace tree to
-                        * the node's parent.
+                        * No more children of this node (acpi_ns_get_next_node failed), go
+                        * back upwards in the namespace tree to the node's parent.
                         */
                        level--;
                        child_node = parent_node;
index dca6799..7ac6ace 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -170,7 +170,6 @@ acpi_evaluate_object(acpi_handle handle,
                     struct acpi_buffer *return_buffer)
 {
        acpi_status status;
-       acpi_status status2;
        struct acpi_evaluate_info *info;
        acpi_size buffer_space_needed;
        u32 i;
@@ -329,14 +328,12 @@ acpi_evaluate_object(acpi_handle handle,
                 * Delete the internal return object. NOTE: Interpreter must be
                 * locked to avoid race condition.
                 */
-               status2 = acpi_ex_enter_interpreter();
-               if (ACPI_SUCCESS(status2)) {
+               acpi_ex_enter_interpreter();
 
-                       /* Remove one reference on the return object (should delete it) */
+               /* Remove one reference on the return object (should delete it) */
 
-                       acpi_ut_remove_reference(info->return_object);
-                       acpi_ex_exit_interpreter();
-               }
+               acpi_ut_remove_reference(info->return_object);
+               acpi_ex_exit_interpreter();
        }
 
       cleanup:
index 978213a..b489781 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -84,38 +84,41 @@ acpi_get_handle(acpi_handle parent,
        /* Convert a parent handle to a prefix node */
 
        if (parent) {
-               status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
-               if (ACPI_FAILURE(status)) {
-                       return (status);
-               }
-
                prefix_node = acpi_ns_map_handle_to_node(parent);
                if (!prefix_node) {
-                       (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
                        return (AE_BAD_PARAMETER);
                }
+       }
+
+       /*
+        * Valid cases are:
+        * 1) Fully qualified pathname
+        * 2) Parent + Relative pathname
+        *
+        * Error for <null Parent + relative path>
+        */
+       if (acpi_ns_valid_root_prefix(pathname[0])) {
 
-               status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
-               if (ACPI_FAILURE(status)) {
-                       return (status);
+               /* Pathname is fully qualified (starts with '\') */
+
+               /* Special case for root-only, since we can't search for it */
+
+               if (!ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH)) {
+                       *ret_handle =
+                           acpi_ns_convert_entry_to_handle(acpi_gbl_root_node);
+                       return (AE_OK);
                }
-       }
+       } else if (!prefix_node) {
 
-       /* Special case for root, since we can't search for it */
+               /* Relative path with null prefix is disallowed */
 
-       if (ACPI_STRCMP(pathname, ACPI_NS_ROOT_PATH) == 0) {
-               *ret_handle =
-                   acpi_ns_convert_entry_to_handle(acpi_gbl_root_node);
-               return (AE_OK);
+               return (AE_BAD_PARAMETER);
        }
 
-       /*
-        *  Find the Node and convert to a handle
-        */
-       status = acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH,
-                                 &node);
+       /* Find the Node and convert to a handle */
 
-       *ret_handle = NULL;
+       status =
+           acpi_ns_get_node(prefix_node, pathname, ACPI_NS_NO_UPSEARCH, &node);
        if (ACPI_SUCCESS(status)) {
                *ret_handle = acpi_ns_convert_entry_to_handle(node);
        }
index a18b1c2..faa3758 100644 (file)
@@ -6,7 +6,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index bd96a70..4a9faff 100644 (file)
@@ -45,7 +45,7 @@ int __cpuinitdata pxm_to_node_map[MAX_PXM_DOMAINS]
 int __cpuinitdata node_to_pxm_map[MAX_NUMNODES]
                                = { [0 ... MAX_NUMNODES - 1] = PXM_INVAL };
 
-extern int __init acpi_table_parse_madt_family(enum acpi_table_id id,
+extern int __init acpi_table_parse_madt_family(char *id,
                                               unsigned long madt_size,
                                               int entry_id,
                                               acpi_madt_entry_handler handler,
@@ -89,7 +89,7 @@ void __cpuinit acpi_unmap_pxm_to_node(int node)
        node_clear(node, nodes_found_map);
 }
 
-void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
+void __init acpi_table_print_srat_entry(struct acpi_subtable_header * header)
 {
 
        ACPI_FUNCTION_NAME("acpi_table_print_srat_entry");
@@ -99,36 +99,35 @@ void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
 
        switch (header->type) {
 
-       case ACPI_SRAT_PROCESSOR_AFFINITY:
+       case ACPI_SRAT_TYPE_CPU_AFFINITY:
 #ifdef ACPI_DEBUG_OUTPUT
                {
-                       struct acpi_table_processor_affinity *p =
-                           (struct acpi_table_processor_affinity *)header;
+                       struct acpi_srat_cpu_affinity *p =
+                           (struct acpi_srat_cpu_affinity *)header;
                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                          "SRAT Processor (id[0x%02x] eid[0x%02x]) in proximity domain %d %s\n",
-                                         p->apic_id, p->lsapic_eid,
-                                         p->proximity_domain,
-                                         p->flags.
-                                         enabled ? "enabled" : "disabled"));
+                                         p->apic_id, p->local_sapic_eid,
+                                         p->proximity_domain_lo,
+                                         (p->flags & ACPI_SRAT_CPU_ENABLED)?
+                                         "enabled" : "disabled"));
                }
 #endif                         /* ACPI_DEBUG_OUTPUT */
                break;
 
-       case ACPI_SRAT_MEMORY_AFFINITY:
+       case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
 #ifdef ACPI_DEBUG_OUTPUT
                {
-                       struct acpi_table_memory_affinity *p =
-                           (struct acpi_table_memory_affinity *)header;
+                       struct acpi_srat_mem_affinity *p =
+                           (struct acpi_srat_mem_affinity *)header;
                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                         "SRAT Memory (0x%08x%08x length 0x%08x%08x type 0x%x) in proximity domain %d %s%s\n",
-                                         p->base_addr_hi, p->base_addr_lo,
-                                         p->length_hi, p->length_lo,
+                                         "SRAT Memory (0x%lx length 0x%lx type 0x%x) in proximity domain %d %s%s\n",
+                                         (unsigned long)p->base_address,
+                                         (unsigned long)p->length,
                                          p->memory_type, p->proximity_domain,
-                                         p->flags.
-                                         enabled ? "enabled" : "disabled",
-                                         p->flags.
-                                         hot_pluggable ? " hot-pluggable" :
-                                         ""));
+                                         (p->flags & ACPI_SRAT_MEM_ENABLED)?
+                                         "enabled" : "disabled",
+                                         (p->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE)?
+                                         " hot-pluggable" : ""));
                }
 #endif                         /* ACPI_DEBUG_OUTPUT */
                break;
@@ -141,18 +140,18 @@ void __init acpi_table_print_srat_entry(acpi_table_entry_header * header)
        }
 }
 
-static int __init acpi_parse_slit(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_slit(struct acpi_table_header *table)
 {
        struct acpi_table_slit *slit;
        u32 localities;
 
-       if (!phys_addr || !size)
+       if (!table)
                return -EINVAL;
 
-       slit = (struct acpi_table_slit *)__va(phys_addr);
+       slit = (struct acpi_table_slit *)table;
 
        /* downcast just for %llu vs %lu for i386/ia64  */
-       localities = (u32) slit->localities;
+       localities = (u32) slit->locality_count;
 
        acpi_numa_slit_init(slit);
 
@@ -160,12 +159,12 @@ static int __init acpi_parse_slit(unsigned long phys_addr, unsigned long size)
 }
 
 static int __init
-acpi_parse_processor_affinity(acpi_table_entry_header * header,
+acpi_parse_processor_affinity(struct acpi_subtable_header * header,
                              const unsigned long end)
 {
-       struct acpi_table_processor_affinity *processor_affinity;
+       struct acpi_srat_cpu_affinity *processor_affinity;
 
-       processor_affinity = (struct acpi_table_processor_affinity *)header;
+       processor_affinity = (struct acpi_srat_cpu_affinity *)header;
        if (!processor_affinity)
                return -EINVAL;
 
@@ -178,12 +177,12 @@ acpi_parse_processor_affinity(acpi_table_entry_header * header,
 }
 
 static int __init
-acpi_parse_memory_affinity(acpi_table_entry_header * header,
+acpi_parse_memory_affinity(struct acpi_subtable_header * header,
                           const unsigned long end)
 {
-       struct acpi_table_memory_affinity *memory_affinity;
+       struct acpi_srat_mem_affinity *memory_affinity;
 
-       memory_affinity = (struct acpi_table_memory_affinity *)header;
+       memory_affinity = (struct acpi_srat_mem_affinity *)header;
        if (!memory_affinity)
                return -EINVAL;
 
@@ -195,23 +194,23 @@ acpi_parse_memory_affinity(acpi_table_entry_header * header,
        return 0;
 }
 
-static int __init acpi_parse_srat(unsigned long phys_addr, unsigned long size)
+static int __init acpi_parse_srat(struct acpi_table_header *table)
 {
        struct acpi_table_srat *srat;
 
-       if (!phys_addr || !size)
+       if (!table)
                return -EINVAL;
 
-       srat = (struct acpi_table_srat *)__va(phys_addr);
+       srat = (struct acpi_table_srat *)table;
 
        return 0;
 }
 
 int __init
-acpi_table_parse_srat(enum acpi_srat_entry_id id,
+acpi_table_parse_srat(enum acpi_srat_type id,
                      acpi_madt_entry_handler handler, unsigned int max_entries)
 {
-       return acpi_table_parse_madt_family(ACPI_SRAT,
+       return acpi_table_parse_madt_family(ACPI_SIG_SRAT,
                                            sizeof(struct acpi_table_srat), id,
                                            handler, max_entries);
 }
@@ -221,17 +220,17 @@ int __init acpi_numa_init(void)
        int result;
 
        /* SRAT: Static Resource Affinity Table */
-       result = acpi_table_parse(ACPI_SRAT, acpi_parse_srat);
+       result = acpi_table_parse(ACPI_SIG_SRAT, acpi_parse_srat);
 
        if (result > 0) {
-               result = acpi_table_parse_srat(ACPI_SRAT_PROCESSOR_AFFINITY,
+               result = acpi_table_parse_srat(ACPI_SRAT_TYPE_CPU_AFFINITY,
                                               acpi_parse_processor_affinity,
                                               NR_CPUS);
-               result = acpi_table_parse_srat(ACPI_SRAT_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS); // IA64 specific
+               result = acpi_table_parse_srat(ACPI_SRAT_TYPE_MEMORY_AFFINITY, acpi_parse_memory_affinity, NR_NODE_MEMBLKS);    // IA64 specific
        }
 
        /* SLIT: System Locality Information Table */
-       result = acpi_table_parse(ACPI_SLIT, acpi_parse_slit);
+       result = acpi_table_parse(ACPI_SIG_SLIT, acpi_parse_slit);
 
        acpi_numa_arch_fixup();
        return 0;
index 57ae1e5..0f6f3bc 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/nmi.h>
+#include <linux/acpi.h>
 #include <acpi/acpi.h>
 #include <asm/io.h>
 #include <acpi/acpi_bus.h>
@@ -75,6 +76,54 @@ static acpi_osd_handler acpi_irq_handler;
 static void *acpi_irq_context;
 static struct workqueue_struct *kacpid_wq;
 
+static void __init acpi_request_region (struct acpi_generic_address *addr,
+       unsigned int length, char *desc)
+{
+       struct resource *res;
+
+       if (!addr->address || !length)
+               return;
+
+       if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
+               res = request_region(addr->address, length, desc);
+       else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+               res = request_mem_region(addr->address, length, desc);
+}
+
+static int __init acpi_reserve_resources(void)
+{
+       acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
+               "ACPI PM1a_EVT_BLK");
+
+       acpi_request_region(&acpi_gbl_FADT.xpm1b_event_block, acpi_gbl_FADT.pm1_event_length,
+               "ACPI PM1b_EVT_BLK");
+
+       acpi_request_region(&acpi_gbl_FADT.xpm1a_control_block, acpi_gbl_FADT.pm1_control_length,
+               "ACPI PM1a_CNT_BLK");
+
+       acpi_request_region(&acpi_gbl_FADT.xpm1b_control_block, acpi_gbl_FADT.pm1_control_length,
+               "ACPI PM1b_CNT_BLK");
+
+       if (acpi_gbl_FADT.pm_timer_length == 4)
+               acpi_request_region(&acpi_gbl_FADT.xpm_timer_block, 4, "ACPI PM_TMR");
+
+       acpi_request_region(&acpi_gbl_FADT.xpm2_control_block, acpi_gbl_FADT.pm2_control_length,
+               "ACPI PM2_CNT_BLK");
+
+       /* Length of GPE blocks must be a non-negative multiple of 2 */
+
+       if (!(acpi_gbl_FADT.gpe0_block_length & 0x1))
+               acpi_request_region(&acpi_gbl_FADT.xgpe0_block,
+                              acpi_gbl_FADT.gpe0_block_length, "ACPI GPE0_BLK");
+
+       if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
+               acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
+                              acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
+
+       return 0;
+}
+device_initcall(acpi_reserve_resources);
+
 acpi_status acpi_os_initialize(void)
 {
        return AE_OK;
@@ -136,53 +185,43 @@ void acpi_os_vprintf(const char *fmt, va_list args)
 #endif
 }
 
-acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr)
+acpi_physical_address __init acpi_os_get_root_pointer(void)
 {
        if (efi_enabled) {
-               addr->pointer_type = ACPI_PHYSICAL_POINTER;
                if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
-                       addr->pointer.physical = efi.acpi20;
+                       return efi.acpi20;
                else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
-                       addr->pointer.physical = efi.acpi;
+                       return efi.acpi;
                else {
                        printk(KERN_ERR PREFIX
                               "System description tables not found\n");
-                       return AE_NOT_FOUND;
+                       return 0;
                }
-       } else {
-               if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
-                       printk(KERN_ERR PREFIX
-                              "System description tables not found\n");
-                       return AE_NOT_FOUND;
-               }
-       }
-
-       return AE_OK;
+       } else
+               return acpi_find_rsdp();
 }
 
-acpi_status
-acpi_os_map_memory(acpi_physical_address phys, acpi_size size,
-                  void __iomem ** virt)
+void __iomem *acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 {
        if (phys > ULONG_MAX) {
                printk(KERN_ERR PREFIX "Cannot map memory that high\n");
-               return AE_BAD_PARAMETER;
+               return 0;
        }
-       /*
-        * ioremap checks to ensure this is in reserved space
-        */
-       *virt = ioremap((unsigned long)phys, size);
-
-       if (!*virt)
-               return AE_NO_MEMORY;
-
-       return AE_OK;
+       if (acpi_gbl_permanent_mmap)
+               /*
+               * ioremap checks to ensure this is in reserved space
+               */
+               return ioremap((unsigned long)phys, size);
+       else
+               return __acpi_map_table((unsigned long)phys, size);
 }
 EXPORT_SYMBOL_GPL(acpi_os_map_memory);
 
 void acpi_os_unmap_memory(void __iomem * virt, acpi_size size)
 {
-       iounmap(virt);
+       if (acpi_gbl_permanent_mmap) {
+               iounmap(virt);
+       }
 }
 EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
 
@@ -254,7 +293,7 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
         * FADT. It may not be the same if an interrupt source override exists
         * for the SCI.
         */
-       gsi = acpi_fadt.sci_int;
+       gsi = acpi_gbl_FADT.sci_interrupt;
        if (acpi_gsi_to_irq(gsi, &irq) < 0) {
                printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n",
                       gsi);
index bf88e07..c2b9835 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e1541db..773aee8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 
 /*
- * Parse the AML and build an operation tree as most interpreters,
- * like Perl, do.  Parsing is done by hand rather than with a YACC
- * generated parser to tightly constrain stack and dynamic memory
- * usage.  At the same time, parsing is kept flexible and the code
- * fairly compact by parsing based on a list of AML opcode
- * templates in aml_op_info[]
+ * Parse the AML and build an operation tree as most interpreters, (such as
+ * Perl) do. Parsing is done by hand rather than with a YACC generated parser
+ * to tightly constrain stack and dynamic memory usage. Parsing is kept
+ * flexible and the code fairly compact by parsing based on a list of AML
+ * opcode templates in aml_op_info[].
  */
 
 #include <acpi/acpi.h>
@@ -60,6 +59,761 @@ ACPI_MODULE_NAME("psloop")
 
 static u32 acpi_gbl_depth = 0;
 
+/* Local prototypes */
+
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state);
+
+static acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+                      u8 * aml_op_start,
+                      union acpi_parse_object *unnamed_op,
+                      union acpi_parse_object **op);
+
+static acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+                 u8 * aml_op_start, union acpi_parse_object **new_op);
+
+static acpi_status
+acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
+                     u8 * aml_op_start, union acpi_parse_object *op);
+
+static acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+                   union acpi_parse_object **op, acpi_status status);
+
+static acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+                         union acpi_parse_object *op, acpi_status status);
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_get_aml_opcode
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Extract the next AML opcode from the input stream.
+ *
+ ******************************************************************************/
+
+static acpi_status acpi_ps_get_aml_opcode(struct acpi_walk_state *walk_state)
+{
+
+       ACPI_FUNCTION_TRACE_PTR(ps_get_aml_opcode, walk_state);
+
+       walk_state->aml_offset =
+           (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml,
+                               walk_state->parser_state.aml_start);
+       walk_state->opcode = acpi_ps_peek_opcode(&(walk_state->parser_state));
+
+       /*
+        * First cut to determine what we have found:
+        * 1) A valid AML opcode
+        * 2) A name string
+        * 3) An unknown/invalid opcode
+        */
+       walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
+
+       switch (walk_state->op_info->class) {
+       case AML_CLASS_ASCII:
+       case AML_CLASS_PREFIX:
+               /*
+                * Starts with a valid prefix or ASCII char, this is a name
+                * string. Convert the bare name string to a namepath.
+                */
+               walk_state->opcode = AML_INT_NAMEPATH_OP;
+               walk_state->arg_types = ARGP_NAMESTRING;
+               break;
+
+       case AML_CLASS_UNKNOWN:
+
+               /* The opcode is unrecognized. Just skip unknown opcodes */
+
+               ACPI_ERROR((AE_INFO,
+                           "Found unknown opcode %X at AML address %p offset %X, ignoring",
+                           walk_state->opcode, walk_state->parser_state.aml,
+                           walk_state->aml_offset));
+
+               ACPI_DUMP_BUFFER(walk_state->parser_state.aml, 128);
+
+               /* Assume one-byte bad opcode */
+
+               walk_state->parser_state.aml++;
+               return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+
+       default:
+
+               /* Found opcode info, this is a normal opcode */
+
+               walk_state->parser_state.aml +=
+                   acpi_ps_get_opcode_size(walk_state->opcode);
+               walk_state->arg_types = walk_state->op_info->parse_args;
+               break;
+       }
+
+       return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_build_named_op
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              aml_op_start        - Begin of named Op in AML
+ *              unnamed_op          - Early Op (not a named Op)
+ *              Op                  - Returned Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Parse a named Op
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ps_build_named_op(struct acpi_walk_state *walk_state,
+                      u8 * aml_op_start,
+                      union acpi_parse_object *unnamed_op,
+                      union acpi_parse_object **op)
+{
+       acpi_status status = AE_OK;
+       union acpi_parse_object *arg = NULL;
+
+       ACPI_FUNCTION_TRACE_PTR(ps_build_named_op, walk_state);
+
+       unnamed_op->common.value.arg = NULL;
+       unnamed_op->common.aml_opcode = walk_state->opcode;
+
+       /*
+        * Get and append arguments until we find the node that contains
+        * the name (the type ARGP_NAME).
+        */
+       while (GET_CURRENT_ARG_TYPE(walk_state->arg_types) &&
+              (GET_CURRENT_ARG_TYPE(walk_state->arg_types) != ARGP_NAME)) {
+               status =
+                   acpi_ps_get_next_arg(walk_state,
+                                        &(walk_state->parser_state),
+                                        GET_CURRENT_ARG_TYPE(walk_state->
+                                                             arg_types), &arg);
+               if (ACPI_FAILURE(status)) {
+                       return_ACPI_STATUS(status);
+               }
+
+               acpi_ps_append_arg(unnamed_op, arg);
+               INCREMENT_ARG_LIST(walk_state->arg_types);
+       }
+
+       /*
+        * Make sure that we found a NAME and didn't run out of arguments
+        */
+       if (!GET_CURRENT_ARG_TYPE(walk_state->arg_types)) {
+               return_ACPI_STATUS(AE_AML_NO_OPERAND);
+       }
+
+       /* We know that this arg is a name, move to next arg */
+
+       INCREMENT_ARG_LIST(walk_state->arg_types);
+
+       /*
+        * Find the object. This will either insert the object into
+        * the namespace or simply look it up
+        */
+       walk_state->op = NULL;
+
+       status = walk_state->descending_callback(walk_state, op);
+       if (ACPI_FAILURE(status)) {
+               ACPI_EXCEPTION((AE_INFO, status, "During name lookup/catalog"));
+               return_ACPI_STATUS(status);
+       }
+
+       if (!*op) {
+               return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+       }
+
+       status = acpi_ps_next_parse_state(walk_state, *op, status);
+       if (ACPI_FAILURE(status)) {
+               if (status == AE_CTRL_PENDING) {
+                       return_ACPI_STATUS(AE_CTRL_PARSE_PENDING);
+               }
+               return_ACPI_STATUS(status);
+       }
+
+       acpi_ps_append_arg(*op, unnamed_op->common.value.arg);
+       acpi_gbl_depth++;
+
+       if ((*op)->common.aml_opcode == AML_REGION_OP) {
+               /*
+                * Defer final parsing of an operation_region body, because we don't
+                * have enough info in the first pass to parse it correctly (i.e.,
+                * there may be method calls within the term_arg elements of the body.)
+                *
+                * However, we must continue parsing because the opregion is not a
+                * standalone package -- we don't know where the end is at this point.
+                *
+                * (Length is unknown until parse of the body complete)
+                */
+               (*op)->named.data = aml_op_start;
+               (*op)->named.length = 0;
+       }
+
+       return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_create_op
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              aml_op_start        - Op start in AML
+ *              new_op              - Returned Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get Op from AML
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ps_create_op(struct acpi_walk_state *walk_state,
+                 u8 * aml_op_start, union acpi_parse_object **new_op)
+{
+       acpi_status status = AE_OK;
+       union acpi_parse_object *op;
+       union acpi_parse_object *named_op = NULL;
+
+       ACPI_FUNCTION_TRACE_PTR(ps_create_op, walk_state);
+
+       status = acpi_ps_get_aml_opcode(walk_state);
+       if (status == AE_CTRL_PARSE_CONTINUE) {
+               return_ACPI_STATUS(AE_CTRL_PARSE_CONTINUE);
+       }
+
+       /* Create Op structure and append to parent's argument list */
+
+       walk_state->op_info = acpi_ps_get_opcode_info(walk_state->opcode);
+       op = acpi_ps_alloc_op(walk_state->opcode);
+       if (!op) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
+       }
+
+       if (walk_state->op_info->flags & AML_NAMED) {
+               status =
+                   acpi_ps_build_named_op(walk_state, aml_op_start, op,
+                                          &named_op);
+               acpi_ps_free_op(op);
+               if (ACPI_FAILURE(status)) {
+                       return_ACPI_STATUS(status);
+               }
+
+               *new_op = named_op;
+               return_ACPI_STATUS(AE_OK);
+       }
+
+       /* Not a named opcode, just allocate Op and append to parent */
+
+       if (walk_state->op_info->flags & AML_CREATE) {
+               /*
+                * Backup to beginning of create_xXXfield declaration
+                * body_length is unknown until we parse the body
+                */
+               op->named.data = aml_op_start;
+               op->named.length = 0;
+       }
+
+       acpi_ps_append_arg(acpi_ps_get_parent_scope
+                          (&(walk_state->parser_state)), op);
+
+       if (walk_state->descending_callback != NULL) {
+               /*
+                * Find the object. This will either insert the object into
+                * the namespace or simply look it up
+                */
+               walk_state->op = *new_op = op;
+
+               status = walk_state->descending_callback(walk_state, &op);
+               status = acpi_ps_next_parse_state(walk_state, op, status);
+               if (status == AE_CTRL_PENDING) {
+                       status = AE_CTRL_PARSE_PENDING;
+               }
+       }
+
+       return_ACPI_STATUS(status);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_get_arguments
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              aml_op_start        - Op start in AML
+ *              Op                  - Current Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Get arguments for passed Op.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ps_get_arguments(struct acpi_walk_state *walk_state,
+                     u8 * aml_op_start, union acpi_parse_object *op)
+{
+       acpi_status status = AE_OK;
+       union acpi_parse_object *arg = NULL;
+
+       ACPI_FUNCTION_TRACE_PTR(ps_get_arguments, walk_state);
+
+       switch (op->common.aml_opcode) {
+       case AML_BYTE_OP:       /* AML_BYTEDATA_ARG */
+       case AML_WORD_OP:       /* AML_WORDDATA_ARG */
+       case AML_DWORD_OP:      /* AML_DWORDATA_ARG */
+       case AML_QWORD_OP:      /* AML_QWORDATA_ARG */
+       case AML_STRING_OP:     /* AML_ASCIICHARLIST_ARG */
+
+               /* Fill in constant or string argument directly */
+
+               acpi_ps_get_next_simple_arg(&(walk_state->parser_state),
+                                           GET_CURRENT_ARG_TYPE(walk_state->
+                                                                arg_types),
+                                           op);
+               break;
+
+       case AML_INT_NAMEPATH_OP:       /* AML_NAMESTRING_ARG */
+
+               status =
+                   acpi_ps_get_next_namepath(walk_state,
+                                             &(walk_state->parser_state), op,
+                                             1);
+               if (ACPI_FAILURE(status)) {
+                       return_ACPI_STATUS(status);
+               }
+
+               walk_state->arg_types = 0;
+               break;
+
+       default:
+               /*
+                * Op is not a constant or string, append each argument to the Op
+                */
+               while (GET_CURRENT_ARG_TYPE(walk_state->arg_types)
+                      && !walk_state->arg_count) {
+                       walk_state->aml_offset =
+                           (u32) ACPI_PTR_DIFF(walk_state->parser_state.aml,
+                                               walk_state->parser_state.
+                                               aml_start);
+
+                       status =
+                           acpi_ps_get_next_arg(walk_state,
+                                                &(walk_state->parser_state),
+                                                GET_CURRENT_ARG_TYPE
+                                                (walk_state->arg_types), &arg);
+                       if (ACPI_FAILURE(status)) {
+                               return_ACPI_STATUS(status);
+                       }
+
+                       if (arg) {
+                               arg->common.aml_offset = walk_state->aml_offset;
+                               acpi_ps_append_arg(op, arg);
+                       }
+
+                       INCREMENT_ARG_LIST(walk_state->arg_types);
+               }
+
+               /* Special processing for certain opcodes */
+
+               /* TBD (remove): Temporary mechanism to disable this code if needed */
+
+#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
+
+               if ((walk_state->pass_number <= ACPI_IMODE_LOAD_PASS1) &&
+                   ((walk_state->parse_flags & ACPI_PARSE_DISASSEMBLE) == 0)) {
+                       /*
+                        * We want to skip If/Else/While constructs during Pass1 because we
+                        * want to actually conditionally execute the code during Pass2.
+                        *
+                        * Except for disassembly, where we always want to walk the
+                        * If/Else/While packages
+                        */
+                       switch (op->common.aml_opcode) {
+                       case AML_IF_OP:
+                       case AML_ELSE_OP:
+                       case AML_WHILE_OP:
+
+                               ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
+                                                 "Pass1: Skipping an If/Else/While body\n"));
+
+                               /* Skip body of if/else/while in pass 1 */
+
+                               walk_state->parser_state.aml =
+                                   walk_state->parser_state.pkg_end;
+                               walk_state->arg_count = 0;
+                               break;
+
+                       default:
+                               break;
+                       }
+               }
+#endif
+
+               switch (op->common.aml_opcode) {
+               case AML_METHOD_OP:
+                       /*
+                        * Skip parsing of control method because we don't have enough
+                        * info in the first pass to parse it correctly.
+                        *
+                        * Save the length and address of the body
+                        */
+                       op->named.data = walk_state->parser_state.aml;
+                       op->named.length = (u32)
+                           (walk_state->parser_state.pkg_end -
+                            walk_state->parser_state.aml);
+
+                       /* Skip body of method */
+
+                       walk_state->parser_state.aml =
+                           walk_state->parser_state.pkg_end;
+                       walk_state->arg_count = 0;
+                       break;
+
+               case AML_BUFFER_OP:
+               case AML_PACKAGE_OP:
+               case AML_VAR_PACKAGE_OP:
+
+                       if ((op->common.parent) &&
+                           (op->common.parent->common.aml_opcode ==
+                            AML_NAME_OP)
+                           && (walk_state->pass_number <=
+                               ACPI_IMODE_LOAD_PASS2)) {
+                               /*
+                                * Skip parsing of Buffers and Packages because we don't have
+                                * enough info in the first pass to parse them correctly.
+                                */
+                               op->named.data = aml_op_start;
+                               op->named.length = (u32)
+                                   (walk_state->parser_state.pkg_end -
+                                    aml_op_start);
+
+                               /* Skip body */
+
+                               walk_state->parser_state.aml =
+                                   walk_state->parser_state.pkg_end;
+                               walk_state->arg_count = 0;
+                       }
+                       break;
+
+               case AML_WHILE_OP:
+
+                       if (walk_state->control_state) {
+                               walk_state->control_state->control.package_end =
+                                   walk_state->parser_state.pkg_end;
+                       }
+                       break;
+
+               default:
+
+                       /* No action for all other opcodes */
+                       break;
+               }
+
+               break;
+       }
+
+       return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_complete_op
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              Op                  - Returned Op
+ *              Status              - Parse status before complete Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Complete Op
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ps_complete_op(struct acpi_walk_state *walk_state,
+                   union acpi_parse_object **op, acpi_status status)
+{
+       acpi_status status2;
+
+       ACPI_FUNCTION_TRACE_PTR(ps_complete_op, walk_state);
+
+       /*
+        * Finished one argument of the containing scope
+        */
+       walk_state->parser_state.scope->parse_scope.arg_count--;
+
+       /* Close this Op (will result in parse subtree deletion) */
+
+       status2 = acpi_ps_complete_this_op(walk_state, *op);
+       if (ACPI_FAILURE(status2)) {
+               return_ACPI_STATUS(status2);
+       }
+
+       *op = NULL;
+
+       switch (status) {
+       case AE_OK:
+               break;
+
+       case AE_CTRL_TRANSFER:
+
+               /* We are about to transfer to a called method */
+
+               walk_state->prev_op = NULL;
+               walk_state->prev_arg_types = walk_state->arg_types;
+               return_ACPI_STATUS(status);
+
+       case AE_CTRL_END:
+
+               acpi_ps_pop_scope(&(walk_state->parser_state), op,
+                                 &walk_state->arg_types,
+                                 &walk_state->arg_count);
+
+               if (*op) {
+                       walk_state->op = *op;
+                       walk_state->op_info =
+                           acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+                       walk_state->opcode = (*op)->common.aml_opcode;
+
+                       status = walk_state->ascending_callback(walk_state);
+                       status =
+                           acpi_ps_next_parse_state(walk_state, *op, status);
+
+                       status2 = acpi_ps_complete_this_op(walk_state, *op);
+                       if (ACPI_FAILURE(status2)) {
+                               return_ACPI_STATUS(status2);
+                       }
+               }
+
+               status = AE_OK;
+               break;
+
+       case AE_CTRL_BREAK:
+       case AE_CTRL_CONTINUE:
+
+               /* Pop off scopes until we find the While */
+
+               while (!(*op) || ((*op)->common.aml_opcode != AML_WHILE_OP)) {
+                       acpi_ps_pop_scope(&(walk_state->parser_state), op,
+                                         &walk_state->arg_types,
+                                         &walk_state->arg_count);
+
+                       if ((*op)->common.aml_opcode != AML_WHILE_OP) {
+                               status2 = acpi_ds_result_stack_pop(walk_state);
+                               if (ACPI_FAILURE(status2)) {
+                                       return_ACPI_STATUS(status2);
+                               }
+                       }
+               }
+
+               /* Close this iteration of the While loop */
+
+               walk_state->op = *op;
+               walk_state->op_info =
+                   acpi_ps_get_opcode_info((*op)->common.aml_opcode);
+               walk_state->opcode = (*op)->common.aml_opcode;
+
+               status = walk_state->ascending_callback(walk_state);
+               status = acpi_ps_next_parse_state(walk_state, *op, status);
+
+               status2 = acpi_ps_complete_this_op(walk_state, *op);
+               if (ACPI_FAILURE(status2)) {
+                       return_ACPI_STATUS(status2);
+               }
+
+               status = AE_OK;
+               break;
+
+       case AE_CTRL_TERMINATE:
+
+               /* Clean up */
+               do {
+                       if (*op) {
+                               status2 =
+                                   acpi_ps_complete_this_op(walk_state, *op);
+                               if (ACPI_FAILURE(status2)) {
+                                       return_ACPI_STATUS(status2);
+                               }
+                               status2 = acpi_ds_result_stack_pop(walk_state);
+                               if (ACPI_FAILURE(status2)) {
+                                       return_ACPI_STATUS(status2);
+                               }
+
+                               acpi_ut_delete_generic_state
+                                   (acpi_ut_pop_generic_state
+                                    (&walk_state->control_state));
+                       }
+
+                       acpi_ps_pop_scope(&(walk_state->parser_state), op,
+                                         &walk_state->arg_types,
+                                         &walk_state->arg_count);
+
+               } while (*op);
+
+               return_ACPI_STATUS(AE_OK);
+
+       default:                /* All other non-AE_OK status */
+
+               do {
+                       if (*op) {
+                               status2 =
+                                   acpi_ps_complete_this_op(walk_state, *op);
+                               if (ACPI_FAILURE(status2)) {
+                                       return_ACPI_STATUS(status2);
+                               }
+                       }
+
+                       acpi_ps_pop_scope(&(walk_state->parser_state), op,
+                                         &walk_state->arg_types,
+                                         &walk_state->arg_count);
+
+               } while (*op);
+
+#if 0
+               /*
+                * TBD: Cleanup parse ops on error
+                */
+               if (*op == NULL) {
+                       acpi_ps_pop_scope(parser_state, op,
+                                         &walk_state->arg_types,
+                                         &walk_state->arg_count);
+               }
+#endif
+               walk_state->prev_op = NULL;
+               walk_state->prev_arg_types = walk_state->arg_types;
+               return_ACPI_STATUS(status);
+       }
+
+       /* This scope complete? */
+
+       if (acpi_ps_has_completed_scope(&(walk_state->parser_state))) {
+               acpi_ps_pop_scope(&(walk_state->parser_state), op,
+                                 &walk_state->arg_types,
+                                 &walk_state->arg_count);
+               ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Popped scope, Op=%p\n", *op));
+       } else {
+               *op = NULL;
+       }
+
+       return_ACPI_STATUS(AE_OK);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ps_complete_final_op
+ *
+ * PARAMETERS:  walk_state          - Current state
+ *              Op                  - Current Op
+ *              Status              - Current parse status before complete last
+ *                                    Op
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Complete last Op.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_ps_complete_final_op(struct acpi_walk_state *walk_state,
+                         union acpi_parse_object *op, acpi_status status)
+{
+       acpi_status status2;
+
+       ACPI_FUNCTION_TRACE_PTR(ps_complete_final_op, walk_state);
+
+       /*
+        * Complete the last Op (if not completed), and clear the scope stack.
+        * It is easily possible to end an AML "package" with an unbounded number
+        * of open scopes (such as when several ASL blocks are closed with
+        * sequential closing braces). We want to terminate each one cleanly.
+        */
+       ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n",
+                         op));
+       do {
+               if (op) {
+                       if (walk_state->ascending_callback != NULL) {
+                               walk_state->op = op;
+                               walk_state->op_info =
+                                   acpi_ps_get_opcode_info(op->common.
+                                                           aml_opcode);
+                               walk_state->opcode = op->common.aml_opcode;
+
+                               status =
+                                   walk_state->ascending_callback(walk_state);
+                               status =
+                                   acpi_ps_next_parse_state(walk_state, op,
+                                                            status);
+                               if (status == AE_CTRL_PENDING) {
+                                       status =
+                                           acpi_ps_complete_op(walk_state, &op,
+                                                               AE_OK);
+                                       if (ACPI_FAILURE(status)) {
+                                               return_ACPI_STATUS(status);
+                                       }
+                               }
+
+                               if (status == AE_CTRL_TERMINATE) {
+                                       status = AE_OK;
+
+                                       /* Clean up */
+                                       do {
+                                               if (op) {
+                                                       status2 =
+                                                           acpi_ps_complete_this_op
+                                                           (walk_state, op);
+                                                       if (ACPI_FAILURE
+                                                           (status2)) {
+                                                               return_ACPI_STATUS
+                                                                   (status2);
+                                                       }
+                                               }
+
+                                               acpi_ps_pop_scope(&
+                                                                 (walk_state->
+                                                                  parser_state),
+                                                                 &op,
+                                                                 &walk_state->
+                                                                 arg_types,
+                                                                 &walk_state->
+                                                                 arg_count);
+
+                                       } while (op);
+
+                                       return_ACPI_STATUS(status);
+                               }
+
+                               else if (ACPI_FAILURE(status)) {
+
+                                       /* First error is most important */
+
+                                       (void)
+                                           acpi_ps_complete_this_op(walk_state,
+                                                                    op);
+                                       return_ACPI_STATUS(status);
+                               }
+                       }
+
+                       status2 = acpi_ps_complete_this_op(walk_state, op);
+                       if (ACPI_FAILURE(status2)) {
+                               return_ACPI_STATUS(status2);
+                       }
+               }
+
+               acpi_ps_pop_scope(&(walk_state->parser_state), &op,
+                                 &walk_state->arg_types,
+                                 &walk_state->arg_count);
+
+       } while (op);
+
+       return_ACPI_STATUS(status);
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ps_parse_loop
@@ -76,10 +830,7 @@ static u32 acpi_gbl_depth = 0;
 acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
 {
        acpi_status status = AE_OK;
-       acpi_status status2;
        union acpi_parse_object *op = NULL;     /* current op */
-       union acpi_parse_object *arg = NULL;
-       union acpi_parse_object *pre_op = NULL;
        struct acpi_parse_state *parser_state;
        u8 *aml_op_start = NULL;
 
@@ -128,6 +879,7 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
                                                                "Invoked method did not return a value"));
 
                                        }
+
                                        ACPI_EXCEPTION((AE_INFO, status,
                                                        "GetPredicate Failed"));
                                        return_ACPI_STATUS(status);
@@ -147,228 +899,36 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
 
                        /* We were in the middle of an op */
 
-                       op = walk_state->prev_op;
-                       walk_state->arg_types = walk_state->prev_arg_types;
-               }
-       }
-#endif
-
-       /* Iterative parsing loop, while there is more AML to process: */
-
-       while ((parser_state->aml < parser_state->aml_end) || (op)) {
-               aml_op_start = parser_state->aml;
-               if (!op) {
-
-                       /* Get the next opcode from the AML stream */
-
-                       walk_state->aml_offset =
-                           (u32) ACPI_PTR_DIFF(parser_state->aml,
-                                               parser_state->aml_start);
-                       walk_state->opcode = acpi_ps_peek_opcode(parser_state);
-
-                       /*
-                        * First cut to determine what we have found:
-                        * 1) A valid AML opcode
-                        * 2) A name string
-                        * 3) An unknown/invalid opcode
-                        */
-                       walk_state->op_info =
-                           acpi_ps_get_opcode_info(walk_state->opcode);
-                       switch (walk_state->op_info->class) {
-                       case AML_CLASS_ASCII:
-                       case AML_CLASS_PREFIX:
-                               /*
-                                * Starts with a valid prefix or ASCII char, this is a name
-                                * string.  Convert the bare name string to a namepath.
-                                */
-                               walk_state->opcode = AML_INT_NAMEPATH_OP;
-                               walk_state->arg_types = ARGP_NAMESTRING;
-                               break;
-
-                       case AML_CLASS_UNKNOWN:
-
-                               /* The opcode is unrecognized.  Just skip unknown opcodes */
-
-                               ACPI_ERROR((AE_INFO,
-                                           "Found unknown opcode %X at AML address %p offset %X, ignoring",
-                                           walk_state->opcode,
-                                           parser_state->aml,
-                                           walk_state->aml_offset));
-
-                               ACPI_DUMP_BUFFER(parser_state->aml, 128);
-
-                               /* Assume one-byte bad opcode */
-
-                               parser_state->aml++;
-                               continue;
-
-                       default:
-
-                               /* Found opcode info, this is a normal opcode */
-
-                               parser_state->aml +=
-                                   acpi_ps_get_opcode_size(walk_state->opcode);
-                               walk_state->arg_types =
-                                   walk_state->op_info->parse_args;
-                               break;
-                       }
-
-                       /* Create Op structure and append to parent's argument list */
-
-                       if (walk_state->op_info->flags & AML_NAMED) {
-
-                               /* Allocate a new pre_op if necessary */
-
-                               if (!pre_op) {
-                                       pre_op =
-                                           acpi_ps_alloc_op(walk_state->
-                                                            opcode);
-                                       if (!pre_op) {
-                                               status = AE_NO_MEMORY;
-                                               goto close_this_op;
-                                       }
-                               }
-
-                               pre_op->common.value.arg = NULL;
-                               pre_op->common.aml_opcode = walk_state->opcode;
-
-                               /*
-                                * Get and append arguments until we find the node that contains
-                                * the name (the type ARGP_NAME).
-                                */
-                               while (GET_CURRENT_ARG_TYPE
-                                      (walk_state->arg_types)
-                                      &&
-                                      (GET_CURRENT_ARG_TYPE
-                                       (walk_state->arg_types) != ARGP_NAME)) {
-                                       status =
-                                           acpi_ps_get_next_arg(walk_state,
-                                                                parser_state,
-                                                                GET_CURRENT_ARG_TYPE
-                                                                (walk_state->
-                                                                 arg_types),
-                                                                &arg);
-                                       if (ACPI_FAILURE(status)) {
-                                               goto close_this_op;
-                                       }
-
-                                       acpi_ps_append_arg(pre_op, arg);
-                                       INCREMENT_ARG_LIST(walk_state->
-                                                          arg_types);
-                               }
-
-                               /*
-                                * Make sure that we found a NAME and didn't run out of
-                                * arguments
-                                */
-                               if (!GET_CURRENT_ARG_TYPE
-                                   (walk_state->arg_types)) {
-                                       status = AE_AML_NO_OPERAND;
-                                       goto close_this_op;
-                               }
-
-                               /* We know that this arg is a name, move to next arg */
-
-                               INCREMENT_ARG_LIST(walk_state->arg_types);
-
-                               /*
-                                * Find the object.  This will either insert the object into
-                                * the namespace or simply look it up
-                                */
-                               walk_state->op = NULL;
+                       op = walk_state->prev_op;
+                       walk_state->arg_types = walk_state->prev_arg_types;
+               }
+       }
+#endif
 
-                               status =
-                                   walk_state->descending_callback(walk_state,
-                                                                   &op);
-                               if (ACPI_FAILURE(status)) {
-                                       ACPI_EXCEPTION((AE_INFO, status,
-                                                       "During name lookup/catalog"));
-                                       goto close_this_op;
-                               }
+       /* Iterative parsing loop, while there is more AML to process: */
 
-                               if (!op) {
+       while ((parser_state->aml < parser_state->aml_end) || (op)) {
+               aml_op_start = parser_state->aml;
+               if (!op) {
+                       status =
+                           acpi_ps_create_op(walk_state, aml_op_start, &op);
+                       if (ACPI_FAILURE(status)) {
+                               if (status == AE_CTRL_PARSE_CONTINUE) {
                                        continue;
                                }
 
-                               status =
-                                   acpi_ps_next_parse_state(walk_state, op,
-                                                            status);
-                               if (status == AE_CTRL_PENDING) {
+                               if (status == AE_CTRL_PARSE_PENDING) {
                                        status = AE_OK;
-                                       goto close_this_op;
                                }
 
+                               status =
+                                   acpi_ps_complete_op(walk_state, &op,
+                                                       status);
                                if (ACPI_FAILURE(status)) {
-                                       goto close_this_op;
-                               }
-
-                               acpi_ps_append_arg(op,
-                                                  pre_op->common.value.arg);
-                               acpi_gbl_depth++;
-
-                               if (op->common.aml_opcode == AML_REGION_OP) {
-                                       /*
-                                        * Defer final parsing of an operation_region body,
-                                        * because we don't have enough info in the first pass
-                                        * to parse it correctly (i.e., there may be method
-                                        * calls within the term_arg elements of the body.)
-                                        *
-                                        * However, we must continue parsing because
-                                        * the opregion is not a standalone package --
-                                        * we don't know where the end is at this point.
-                                        *
-                                        * (Length is unknown until parse of the body complete)
-                                        */
-                                       op->named.data = aml_op_start;
-                                       op->named.length = 0;
-                               }
-                       } else {
-                               /* Not a named opcode, just allocate Op and append to parent */
-
-                               walk_state->op_info =
-                                   acpi_ps_get_opcode_info(walk_state->opcode);
-                               op = acpi_ps_alloc_op(walk_state->opcode);
-                               if (!op) {
-                                       status = AE_NO_MEMORY;
-                                       goto close_this_op;
-                               }
-
-                               if (walk_state->op_info->flags & AML_CREATE) {
-                                       /*
-                                        * Backup to beginning of create_xXXfield declaration
-                                        * body_length is unknown until we parse the body
-                                        */
-                                       op->named.data = aml_op_start;
-                                       op->named.length = 0;
+                                       return_ACPI_STATUS(status);
                                }
 
-                               acpi_ps_append_arg(acpi_ps_get_parent_scope
-                                                  (parser_state), op);
-
-                               if ((walk_state->descending_callback != NULL)) {
-                                       /*
-                                        * Find the object. This will either insert the object into
-                                        * the namespace or simply look it up
-                                        */
-                                       walk_state->op = op;
-
-                                       status =
-                                           walk_state->
-                                           descending_callback(walk_state,
-                                                               &op);
-                                       status =
-                                           acpi_ps_next_parse_state(walk_state,
-                                                                    op,
-                                                                    status);
-                                       if (status == AE_CTRL_PENDING) {
-                                               status = AE_OK;
-                                               goto close_this_op;
-                                       }
-
-                                       if (ACPI_FAILURE(status)) {
-                                               goto close_this_op;
-                                       }
-                               }
+                               continue;
                        }
 
                        op->common.aml_offset = walk_state->aml_offset;
@@ -395,172 +955,17 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
 
                        /* Get arguments */
 
-                       switch (op->common.aml_opcode) {
-                       case AML_BYTE_OP:       /* AML_BYTEDATA_ARG */
-                       case AML_WORD_OP:       /* AML_WORDDATA_ARG */
-                       case AML_DWORD_OP:      /* AML_DWORDATA_ARG */
-                       case AML_QWORD_OP:      /* AML_QWORDATA_ARG */
-                       case AML_STRING_OP:     /* AML_ASCIICHARLIST_ARG */
-
-                               /* Fill in constant or string argument directly */
-
-                               acpi_ps_get_next_simple_arg(parser_state,
-                                                           GET_CURRENT_ARG_TYPE
-                                                           (walk_state->
-                                                            arg_types), op);
-                               break;
-
-                       case AML_INT_NAMEPATH_OP:       /* AML_NAMESTRING_ARG */
-
+                       status =
+                           acpi_ps_get_arguments(walk_state, aml_op_start, op);
+                       if (ACPI_FAILURE(status)) {
                                status =
-                                   acpi_ps_get_next_namepath(walk_state,
-                                                             parser_state, op,
-                                                             1);
+                                   acpi_ps_complete_op(walk_state, &op,
+                                                       status);
                                if (ACPI_FAILURE(status)) {
-                                       goto close_this_op;
-                               }
-
-                               walk_state->arg_types = 0;
-                               break;
-
-                       default:
-                               /*
-                                * Op is not a constant or string, append each argument
-                                * to the Op
-                                */
-                               while (GET_CURRENT_ARG_TYPE
-                                      (walk_state->arg_types)
-                                      && !walk_state->arg_count) {
-                                       walk_state->aml_offset = (u32)
-                                           ACPI_PTR_DIFF(parser_state->aml,
-                                                         parser_state->
-                                                         aml_start);
-
-                                       status =
-                                           acpi_ps_get_next_arg(walk_state,
-                                                                parser_state,
-                                                                GET_CURRENT_ARG_TYPE
-                                                                (walk_state->
-                                                                 arg_types),
-                                                                &arg);
-                                       if (ACPI_FAILURE(status)) {
-                                               goto close_this_op;
-                                       }
-
-                                       if (arg) {
-                                               arg->common.aml_offset =
-                                                   walk_state->aml_offset;
-                                               acpi_ps_append_arg(op, arg);
-                                       }
-                                       INCREMENT_ARG_LIST(walk_state->
-                                                          arg_types);
-                               }
-
-                               /* Special processing for certain opcodes */
-
-                               /* TBD (remove): Temporary mechanism to disable this code if needed */
-
-#ifdef ACPI_ENABLE_MODULE_LEVEL_CODE
-
-                               if ((walk_state->pass_number <=
-                                    ACPI_IMODE_LOAD_PASS1)
-                                   &&
-                                   ((walk_state->
-                                     parse_flags & ACPI_PARSE_DISASSEMBLE) ==
-                                    0)) {
-                                       /*
-                                        * We want to skip If/Else/While constructs during Pass1
-                                        * because we want to actually conditionally execute the
-                                        * code during Pass2.
-                                        *
-                                        * Except for disassembly, where we always want to
-                                        * walk the If/Else/While packages
-                                        */
-                                       switch (op->common.aml_opcode) {
-                                       case AML_IF_OP:
-                                       case AML_ELSE_OP:
-                                       case AML_WHILE_OP:
-
-                                               ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
-                                                                 "Pass1: Skipping an If/Else/While body\n"));
-
-                                               /* Skip body of if/else/while in pass 1 */
-
-                                               parser_state->aml =
-                                                   parser_state->pkg_end;
-                                               walk_state->arg_count = 0;
-                                               break;
-
-                                       default:
-                                               break;
-                                       }
+                                       return_ACPI_STATUS(status);
                                }
-#endif
-                               switch (op->common.aml_opcode) {
-                               case AML_METHOD_OP:
-
-                                       /*
-                                        * Skip parsing of control method
-                                        * because we don't have enough info in the first pass
-                                        * to parse it correctly.
-                                        *
-                                        * Save the length and address of the body
-                                        */
-                                       op->named.data = parser_state->aml;
-                                       op->named.length =
-                                           (u32) (parser_state->pkg_end -
-                                                  parser_state->aml);
-
-                                       /* Skip body of method */
-
-                                       parser_state->aml =
-                                           parser_state->pkg_end;
-                                       walk_state->arg_count = 0;
-                                       break;
-
-                               case AML_BUFFER_OP:
-                               case AML_PACKAGE_OP:
-                               case AML_VAR_PACKAGE_OP:
-
-                                       if ((op->common.parent) &&
-                                           (op->common.parent->common.
-                                            aml_opcode == AML_NAME_OP)
-                                           && (walk_state->pass_number <=
-                                               ACPI_IMODE_LOAD_PASS2)) {
-                                               /*
-                                                * Skip parsing of Buffers and Packages
-                                                * because we don't have enough info in the first pass
-                                                * to parse them correctly.
-                                                */
-                                               op->named.data = aml_op_start;
-                                               op->named.length =
-                                                   (u32) (parser_state->
-                                                          pkg_end -
-                                                          aml_op_start);
-
-                                               /* Skip body */
-
-                                               parser_state->aml =
-                                                   parser_state->pkg_end;
-                                               walk_state->arg_count = 0;
-                                       }
-                                       break;
-
-                               case AML_WHILE_OP:
 
-                                       if (walk_state->control_state) {
-                                               walk_state->control_state->
-                                                   control.package_end =
-                                                   parser_state->pkg_end;
-                                       }
-                                       break;
-
-                               default:
-
-                                       /* No action for all other opcodes */
-                                       break;
-                               }
-                               break;
+                               continue;
                        }
                }
 
@@ -575,8 +980,16 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
                                                    walk_state->arg_types,
                                                    walk_state->arg_count);
                        if (ACPI_FAILURE(status)) {
-                               goto close_this_op;
+                               status =
+                                   acpi_ps_complete_op(walk_state, &op,
+                                                       status);
+                               if (ACPI_FAILURE(status)) {
+                                       return_ACPI_STATUS(status);
+                               }
+
+                               continue;
                        }
+
                        op = NULL;
                        continue;
                }
@@ -628,269 +1041,16 @@ acpi_status acpi_ps_parse_loop(struct acpi_walk_state *walk_state)
                            acpi_ps_next_parse_state(walk_state, op, status);
                        if (status == AE_CTRL_PENDING) {
                                status = AE_OK;
-                               goto close_this_op;
                        }
                }
 
-             close_this_op:
-               /*
-                * Finished one argument of the containing scope
-                */
-               parser_state->scope->parse_scope.arg_count--;
-
-               /* Finished with pre_op */
-
-               if (pre_op) {
-                       acpi_ps_free_op(pre_op);
-                       pre_op = NULL;
-               }
-
-               /* Close this Op (will result in parse subtree deletion) */
-
-               status2 = acpi_ps_complete_this_op(walk_state, op);
-               if (ACPI_FAILURE(status2)) {
-                       return_ACPI_STATUS(status2);
-               }
-               op = NULL;
-
-               switch (status) {
-               case AE_OK:
-                       break;
-
-               case AE_CTRL_TRANSFER:
-
-                       /* We are about to transfer to a called method. */
-
-                       walk_state->prev_op = op;
-                       walk_state->prev_arg_types = walk_state->arg_types;
-                       return_ACPI_STATUS(status);
-
-               case AE_CTRL_END:
-
-                       acpi_ps_pop_scope(parser_state, &op,
-                                         &walk_state->arg_types,
-                                         &walk_state->arg_count);
-
-                       if (op) {
-                               walk_state->op = op;
-                               walk_state->op_info =
-                                   acpi_ps_get_opcode_info(op->common.
-                                                           aml_opcode);
-                               walk_state->opcode = op->common.aml_opcode;
-
-                               status =
-                                   walk_state->ascending_callback(walk_state);
-                               status =
-                                   acpi_ps_next_parse_state(walk_state, op,
-                                                            status);
-
-                               status2 =
-                                   acpi_ps_complete_this_op(walk_state, op);
-                               if (ACPI_FAILURE(status2)) {
-                                       return_ACPI_STATUS(status2);
-                               }
-                               op = NULL;
-                       }
-                       status = AE_OK;
-                       break;
-
-               case AE_CTRL_BREAK:
-               case AE_CTRL_CONTINUE:
-
-                       /* Pop off scopes until we find the While */
-
-                       while (!op || (op->common.aml_opcode != AML_WHILE_OP)) {
-                               acpi_ps_pop_scope(parser_state, &op,
-                                                 &walk_state->arg_types,
-                                                 &walk_state->arg_count);
-
-                               if (op->common.aml_opcode != AML_WHILE_OP) {
-                                       status2 =
-                                           acpi_ds_result_stack_pop
-                                           (walk_state);
-                                       if (ACPI_FAILURE(status2)) {
-                                               return_ACPI_STATUS(status2);
-                                       }
-                               }
-                       }
-
-                       /* Close this iteration of the While loop */
-
-                       walk_state->op = op;
-                       walk_state->op_info =
-                           acpi_ps_get_opcode_info(op->common.aml_opcode);
-                       walk_state->opcode = op->common.aml_opcode;
-
-                       status = walk_state->ascending_callback(walk_state);
-                       status =
-                           acpi_ps_next_parse_state(walk_state, op, status);
-
-                       status2 = acpi_ps_complete_this_op(walk_state, op);
-                       if (ACPI_FAILURE(status2)) {
-                               return_ACPI_STATUS(status2);
-                       }
-                       op = NULL;
-
-                       status = AE_OK;
-                       break;
-
-               case AE_CTRL_TERMINATE:
-
-                       status = AE_OK;
-
-                       /* Clean up */
-                       do {
-                               if (op) {
-                                       status2 =
-                                           acpi_ps_complete_this_op(walk_state,
-                                                                    op);
-                                       if (ACPI_FAILURE(status2)) {
-                                               return_ACPI_STATUS(status2);
-                                       }
-
-                                       status2 =
-                                           acpi_ds_result_stack_pop
-                                           (walk_state);
-                                       if (ACPI_FAILURE(status2)) {
-                                               return_ACPI_STATUS(status2);
-                                       }
-
-                                       acpi_ut_delete_generic_state
-                                           (acpi_ut_pop_generic_state
-                                            (&walk_state->control_state));
-                               }
-
-                               acpi_ps_pop_scope(parser_state, &op,
-                                                 &walk_state->arg_types,
-                                                 &walk_state->arg_count);
-
-                       } while (op);
-
-                       return_ACPI_STATUS(status);
-
-               default:        /* All other non-AE_OK status */
-
-                       do {
-                               if (op) {
-                                       status2 =
-                                           acpi_ps_complete_this_op(walk_state,
-                                                                    op);
-                                       if (ACPI_FAILURE(status2)) {
-                                               return_ACPI_STATUS(status2);
-                                       }
-                               }
-
-                               acpi_ps_pop_scope(parser_state, &op,
-                                                 &walk_state->arg_types,
-                                                 &walk_state->arg_count);
-
-                       } while (op);
-
-                       /*
-                        * TBD: Cleanup parse ops on error
-                        */
-#if 0
-                       if (op == NULL) {
-                               acpi_ps_pop_scope(parser_state, &op,
-                                                 &walk_state->arg_types,
-                                                 &walk_state->arg_count);
-                       }
-#endif
-                       walk_state->prev_op = op;
-                       walk_state->prev_arg_types = walk_state->arg_types;
+               status = acpi_ps_complete_op(walk_state, &op, status);
+               if (ACPI_FAILURE(status)) {
                        return_ACPI_STATUS(status);
                }
 
-               /* This scope complete? */
-
-               if (acpi_ps_has_completed_scope(parser_state)) {
-                       acpi_ps_pop_scope(parser_state, &op,
-                                         &walk_state->arg_types,
-                                         &walk_state->arg_count);
-                       ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
-                                         "Popped scope, Op=%p\n", op));
-               } else {
-                       op = NULL;
-               }
-
        }                       /* while parser_state->Aml */
 
-       /*
-        * Complete the last Op (if not completed), and clear the scope stack.
-        * It is easily possible to end an AML "package" with an unbounded number
-        * of open scopes (such as when several ASL blocks are closed with
-        * sequential closing braces).  We want to terminate each one cleanly.
-        */
-       ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "AML package complete at Op %p\n",
-                         op));
-       do {
-               if (op) {
-                       if (walk_state->ascending_callback != NULL) {
-                               walk_state->op = op;
-                               walk_state->op_info =
-                                   acpi_ps_get_opcode_info(op->common.
-                                                           aml_opcode);
-                               walk_state->opcode = op->common.aml_opcode;
-
-                               status =
-                                   walk_state->ascending_callback(walk_state);
-                               status =
-                                   acpi_ps_next_parse_state(walk_state, op,
-                                                            status);
-                               if (status == AE_CTRL_PENDING) {
-                                       status = AE_OK;
-                                       goto close_this_op;
-                               }
-
-                               if (status == AE_CTRL_TERMINATE) {
-                                       status = AE_OK;
-
-                                       /* Clean up */
-                                       do {
-                                               if (op) {
-                                                       status2 =
-                                                           acpi_ps_complete_this_op
-                                                           (walk_state, op);
-                                                       if (ACPI_FAILURE
-                                                           (status2)) {
-                                                               return_ACPI_STATUS
-                                                                   (status2);
-                                                       }
-                                               }
-
-                                               acpi_ps_pop_scope(parser_state,
-                                                                 &op,
-                                                                 &walk_state->
-                                                                 arg_types,
-                                                                 &walk_state->
-                                                                 arg_count);
-
-                                       } while (op);
-
-                                       return_ACPI_STATUS(status);
-                               }
-
-                               else if (ACPI_FAILURE(status)) {
-
-                                       /* First error is most important */
-
-                                       (void)
-                                           acpi_ps_complete_this_op(walk_state,
-                                                                    op);
-                                       return_ACPI_STATUS(status);
-                               }
-                       }
-
-                       status2 = acpi_ps_complete_this_op(walk_state, op);
-                       if (ACPI_FAILURE(status2)) {
-                               return_ACPI_STATUS(status2);
-                       }
-               }
-
-               acpi_ps_pop_scope(parser_state, &op, &walk_state->arg_types,
-                                 &walk_state->arg_count);
-
-       } while (op);
-
+       status = acpi_ps_complete_final_op(walk_state, op, status);
        return_ACPI_STATUS(status);
 }
index 4bd25e3..16d8b6c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a02aa62..5d63f48 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -540,6 +540,11 @@ acpi_status acpi_ps_parse_aml(struct acpi_walk_state *walk_state)
 
                        if ((status == AE_ALREADY_EXISTS) &&
                            (!walk_state->method_desc->method.mutex)) {
+                               ACPI_INFO((AE_INFO,
+                                          "Marking method %4.4s as Serialized",
+                                          walk_state->method_node->name.
+                                          ascii));
+
                                /*
                                 * Method tried to create an object twice. The probable cause is
                                 * that the method cannot handle reentrancy.
index a3e0314..77cfa4e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0015717..966e7ea 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d405387..8ca5200 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a84a547..49f9757 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5d996c1..94103bc 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -54,8 +54,6 @@ static void acpi_ps_start_trace(struct acpi_evaluate_info *info);
 
 static void acpi_ps_stop_trace(struct acpi_evaluate_info *info);
 
-static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info);
-
 static void
 acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action);
 
@@ -215,6 +213,8 @@ static void acpi_ps_stop_trace(struct acpi_evaluate_info *info)
 acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
 {
        acpi_status status;
+       union acpi_parse_object *op;
+       struct acpi_walk_state *walk_state;
 
        ACPI_FUNCTION_TRACE(ps_execute_method);
 
@@ -234,8 +234,7 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
        }
 
        /*
-        * The caller "owns" the parameters, so give each one an extra
-        * reference
+        * The caller "owns" the parameters, so give each one an extra reference
         */
        acpi_ps_update_parameter_list(info, REF_INCREMENT);
 
@@ -244,30 +243,50 @@ acpi_status acpi_ps_execute_method(struct acpi_evaluate_info *info)
        acpi_ps_start_trace(info);
 
        /*
-        * 1) Perform the first pass parse of the method to enter any
-        *    named objects that it creates into the namespace
+        * Execute the method. Performs parse simultaneously
         */
        ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
-                         "**** Begin Method Parse **** Entry=%p obj=%p\n",
-                         info->resolved_node, info->obj_desc));
+                         "**** Begin Method Parse/Execute [%4.4s] **** Node=%p Obj=%p\n",
+                         info->resolved_node->name.ascii, info->resolved_node,
+                         info->obj_desc));
+
+       /* Create and init a Root Node */
+
+       op = acpi_ps_create_scope_op();
+       if (!op) {
+               status = AE_NO_MEMORY;
+               goto cleanup;
+       }
+
+       /* Create and initialize a new walk state */
+
+       info->pass_number = ACPI_IMODE_EXECUTE;
+       walk_state =
+           acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL,
+                                     NULL, NULL);
+       if (!walk_state) {
+               status = AE_NO_MEMORY;
+               goto cleanup;
+       }
 
-       info->pass_number = 1;
-       status = acpi_ps_execute_pass(info);
+       status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node,
+                                      info->obj_desc->method.aml_start,
+                                      info->obj_desc->method.aml_length, info,
+                                      info->pass_number);
        if (ACPI_FAILURE(status)) {
+               acpi_ds_delete_walk_state(walk_state);
                goto cleanup;
        }
 
-       /*
-        * 2) Execute the method. Performs second pass parse simultaneously
-        */
-       ACPI_DEBUG_PRINT((ACPI_DB_PARSE,
-                         "**** Begin Method Execution **** Entry=%p obj=%p\n",
-                         info->resolved_node, info->obj_desc));
+       /* Parse the AML */
 
-       info->pass_number = 3;
-       status = acpi_ps_execute_pass(info);
+       status = acpi_ps_parse_aml(walk_state);
+
+       /* walk_state was deleted by parse_aml */
 
       cleanup:
+       acpi_ps_delete_parse_tree(op);
+
        /* End optional tracing */
 
        acpi_ps_stop_trace(info);
@@ -330,62 +349,3 @@ acpi_ps_update_parameter_list(struct acpi_evaluate_info *info, u16 action)
                }
        }
 }
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ps_execute_pass
- *
- * PARAMETERS:  Info            - See struct acpi_evaluate_info
- *                                (Used: pass_number, Node, and obj_desc)
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Single AML pass: Parse or Execute a control method
- *
- ******************************************************************************/
-
-static acpi_status acpi_ps_execute_pass(struct acpi_evaluate_info *info)
-{
-       acpi_status status;
-       union acpi_parse_object *op;
-       struct acpi_walk_state *walk_state;
-
-       ACPI_FUNCTION_TRACE(ps_execute_pass);
-
-       /* Create and init a Root Node */
-
-       op = acpi_ps_create_scope_op();
-       if (!op) {
-               return_ACPI_STATUS(AE_NO_MEMORY);
-       }
-
-       /* Create and initialize a new walk state */
-
-       walk_state =
-           acpi_ds_create_walk_state(info->obj_desc->method.owner_id, NULL,
-                                     NULL, NULL);
-       if (!walk_state) {
-               status = AE_NO_MEMORY;
-               goto cleanup;
-       }
-
-       status = acpi_ds_init_aml_walk(walk_state, op, info->resolved_node,
-                                      info->obj_desc->method.aml_start,
-                                      info->obj_desc->method.aml_length,
-                                      info->pass_number == 1 ? NULL : info,
-                                      info->pass_number);
-       if (ACPI_FAILURE(status)) {
-               acpi_ds_delete_walk_state(walk_state);
-               goto cleanup;
-       }
-
-       /* Parse the AML */
-
-       status = acpi_ps_parse_aml(walk_state);
-
-       /* Walk state was deleted by parse_aml */
-
-      cleanup:
-       acpi_ps_delete_parse_tree(op);
-       return_ACPI_STATUS(status);
-}
index 481e633..0f683c8 100644 (file)
@@ -513,7 +513,7 @@ int __init acpi_irq_penalty_init(void)
                }
        }
        /* Add a penalty for the SCI */
-       acpi_irq_penalty[acpi_fadt.sci_int] += PIRQ_PENALTY_PCI_USING;
+       acpi_irq_penalty[acpi_gbl_FADT.sci_interrupt] += PIRQ_PENALTY_PCI_USING;
 
        return 0;
 }
@@ -785,7 +785,7 @@ static int irqrouter_resume(struct sys_device *dev)
 
 
        /* Make sure SCI is enabled again (Apple firmware bug?) */
-       acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1, ACPI_MTX_DO_NOT_LOCK);
+       acpi_set_register(ACPI_BITREG_SCI_ENABLE, 1);
 
        list_for_each(node, &acpi_link.entries) {
                link = list_entry(node, struct acpi_pci_link, node);
index a860efa..4ecf701 100644 (file)
@@ -117,6 +117,19 @@ void acpi_pci_unregister_driver(struct acpi_pci_driver *driver)
 
 EXPORT_SYMBOL(acpi_pci_unregister_driver);
 
+acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
+{
+       struct acpi_pci_root *tmp;
+       
+       list_for_each_entry(tmp, &acpi_pci_roots, node) {
+               if ((tmp->id.segment == (u16) seg) && (tmp->id.bus == (u16) bus))
+                       return tmp->device->handle;
+       }
+       return NULL;            
+}
+
+EXPORT_SYMBOL_GPL(acpi_get_pci_rootbridge_handle);
+
 static acpi_status
 get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
 {
@@ -152,6 +165,21 @@ static acpi_status try_get_root_bridge_busnr(acpi_handle handle, int *busnum)
        return AE_OK;
 }
 
+static void acpi_pci_bridge_scan(struct acpi_device *device)
+{
+       int status;
+       struct acpi_device *child = NULL;
+
+       if (device->flags.bus_address)
+               if (device->parent && device->parent->ops.bind) {
+                       status = device->parent->ops.bind(device);
+                       if (!status) {
+                               list_for_each_entry(child, &device->children, node)
+                                       acpi_pci_bridge_scan(child);
+                       }
+               }
+}
+
 static int acpi_pci_root_add(struct acpi_device *device)
 {
        int result = 0;
@@ -160,6 +188,7 @@ static int acpi_pci_root_add(struct acpi_device *device)
        acpi_status status = AE_OK;
        unsigned long value = 0;
        acpi_handle handle = NULL;
+       struct acpi_device *child;
 
 
        if (!device)
@@ -175,9 +204,6 @@ static int acpi_pci_root_add(struct acpi_device *device)
        strcpy(acpi_device_class(device), ACPI_PCI_ROOT_CLASS);
        acpi_driver_data(device) = root;
 
-       /*
-        * TBD: Doesn't the bus driver automatically set this?
-        */
        device->ops.bind = acpi_pci_bind;
 
        /* 
@@ -299,6 +325,12 @@ static int acpi_pci_root_add(struct acpi_device *device)
                result = acpi_pci_irq_add_prt(device->handle, root->id.segment,
                                              root->id.bus);
 
+       /*
+        * Scan and bind all _ADR-Based Devices
+        */
+       list_for_each_entry(child, &device->children, node)
+               acpi_pci_bridge_scan(child);
+
       end:
        if (result) {
                if (!list_empty(&root->node))
index 5f9496d..0079bc5 100644 (file)
@@ -375,30 +375,126 @@ static int acpi_processor_remove_fs(struct acpi_device *device)
 }
 
 /* Use the acpiid in MADT to map cpus in case of SMP */
+
 #ifndef CONFIG_SMP
-#define convert_acpiid_to_cpu(acpi_id) (-1)
+static int get_cpu_id(acpi_handle handle, u32 acpi_id) {return -1;}
 #else
 
+static struct acpi_table_madt *madt;
+
+static int map_lapic_id(struct acpi_subtable_header *entry,
+                u32 acpi_id, int *apic_id)
+{
+       struct acpi_madt_local_apic *lapic =
+               (struct acpi_madt_local_apic *)entry;
+       if ((lapic->lapic_flags & ACPI_MADT_ENABLED) &&
+           lapic->processor_id == acpi_id) {
+               *apic_id = lapic->id;
+               return 1;
+       }
+       return 0;
+}
+
+static int map_lsapic_id(struct acpi_subtable_header *entry,
+                 u32 acpi_id, int *apic_id)
+{
+       struct acpi_madt_local_sapic *lsapic =
+               (struct acpi_madt_local_sapic *)entry;
+       /* Only check enabled APICs*/
+       if (lsapic->lapic_flags & ACPI_MADT_ENABLED) {
+               /* First check against id */
+               if (lsapic->processor_id == acpi_id) {
+                       *apic_id = lsapic->id;
+                       return 1;
+               /* Check against optional uid */
+               } else if (entry->length >= 16 &&
+                       lsapic->uid == acpi_id) {
+                       *apic_id = lsapic->uid;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
 #ifdef CONFIG_IA64
-#define arch_acpiid_to_apicid  ia64_acpiid_to_sapicid
 #define arch_cpu_to_apicid     ia64_cpu_to_sapicid
-#define ARCH_BAD_APICID                (0xffff)
 #else
-#define arch_acpiid_to_apicid  x86_acpiid_to_apicid
 #define arch_cpu_to_apicid     x86_cpu_to_apicid
-#define ARCH_BAD_APICID                (0xff)
 #endif
 
-static int convert_acpiid_to_cpu(u8 acpi_id)
+static int map_madt_entry(u32 acpi_id)
+{
+       unsigned long madt_end, entry;
+       int apic_id = -1;
+
+       if (!madt)
+               return apic_id;
+
+       entry = (unsigned long)madt;
+       madt_end = entry + madt->header.length;
+
+       /* Parse all entries looking for a match. */
+
+       entry += sizeof(struct acpi_table_madt);
+       while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
+               struct acpi_subtable_header *header =
+                       (struct acpi_subtable_header *)entry;
+               if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
+                       if (map_lapic_id(header, acpi_id, &apic_id))
+                               break;
+               } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
+                       if (map_lsapic_id(header, acpi_id, &apic_id))
+                               break;
+               }
+               entry += header->length;
+       }
+       return apic_id;
+}
+
+static int map_mat_entry(acpi_handle handle, u32 acpi_id)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *obj;
+       struct acpi_subtable_header *header;
+       int apic_id = -1;
+
+       if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
+               goto exit;
+
+       if (!buffer.length || !buffer.pointer)
+               goto exit;
+
+       obj = buffer.pointer;
+       if (obj->type != ACPI_TYPE_BUFFER ||
+           obj->buffer.length < sizeof(struct acpi_subtable_header)) {
+               goto exit;
+       }
+
+       header = (struct acpi_subtable_header *)obj->buffer.pointer;
+       if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
+               map_lapic_id(header, acpi_id, &apic_id);
+       } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
+               map_lsapic_id(header, acpi_id, &apic_id);
+       }
+
+exit:
+       if (buffer.pointer)
+               kfree(buffer.pointer);
+       return apic_id;
+}
+
+static int get_cpu_id(acpi_handle handle, u32 acpi_id)
 {
-       u16 apic_id;
        int i;
+       int apic_id = -1;
 
-       apic_id = arch_acpiid_to_apicid[acpi_id];
-       if (apic_id == ARCH_BAD_APICID)
-               return -1;
+       apic_id = map_mat_entry(handle, acpi_id);
+       if (apic_id == -1)
+               apic_id = map_madt_entry(acpi_id);
+       if (apic_id == -1)
+               return apic_id;
 
-       for (i = 0; i < NR_CPUS; i++) {
+       for (i = 0; i < NR_CPUS; ++i) {
                if (arch_cpu_to_apicid[i] == apic_id)
                        return i;
        }
@@ -410,7 +506,7 @@ static int convert_acpiid_to_cpu(u8 acpi_id)
                                  Driver Interface
    -------------------------------------------------------------------------- */
 
-static int acpi_processor_get_info(struct acpi_processor *pr)
+static int acpi_processor_get_info(struct acpi_processor *pr, unsigned has_uid)
 {
        acpi_status status = 0;
        union acpi_object object = { 0 };
@@ -431,7 +527,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
         * Check to see if we have bus mastering arbitration control.  This
         * is required for proper C3 usage (to maintain cache coherency).
         */
-       if (acpi_fadt.V1_pm2_cnt_blk && acpi_fadt.pm2_cnt_len) {
+       if (acpi_gbl_FADT.pm2_control_block && acpi_gbl_FADT.pm2_control_length) {
                pr->flags.bm_control = 1;
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "Bus mastering arbitration control present\n"));
@@ -439,24 +535,35 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                  "No bus mastering arbitration control\n"));
 
-       /*
-        * Evalute the processor object.  Note that it is common on SMP to
-        * have the first (boot) processor with a valid PBLK address while
-        * all others have a NULL address.
-        */
-       status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
-       if (ACPI_FAILURE(status)) {
-               printk(KERN_ERR PREFIX "Evaluating processor object\n");
-               return -ENODEV;
-       }
-
-       /*
-        * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
-        *      >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c
-        */
-       pr->acpi_id = object.processor.proc_id;
+       /* Check if it is a Device with HID and UID */
+       if (has_uid) {
+               unsigned long value;
+               status = acpi_evaluate_integer(pr->handle, METHOD_NAME__UID,
+                                               NULL, &value);
+               if (ACPI_FAILURE(status)) {
+                       printk(KERN_ERR PREFIX "Evaluating processor _UID\n");
+                       return -ENODEV;
+               }
+               pr->acpi_id = value;
+       } else {
+               /*
+               * Evalute the processor object.  Note that it is common on SMP to
+               * have the first (boot) processor with a valid PBLK address while
+               * all others have a NULL address.
+               */
+               status = acpi_evaluate_object(pr->handle, NULL, NULL, &buffer);
+               if (ACPI_FAILURE(status)) {
+                       printk(KERN_ERR PREFIX "Evaluating processor object\n");
+                       return -ENODEV;
+               }
 
-       cpu_index = convert_acpiid_to_cpu(pr->acpi_id);
+               /*
+               * TBD: Synch processor ID (via LAPIC/LSAPIC structures) on SMP.
+               *      >>> 'acpi_get_processor_id(acpi_id, &id)' in arch/xxx/acpi.c
+               */
+               pr->acpi_id = object.processor.proc_id;
+       }
+       cpu_index = get_cpu_id(pr->handle, pr->acpi_id);
 
        /* Handle UP system running SMP kernel, with no LAPIC in MADT */
        if (!cpu0_initialized && (cpu_index == -1) &&
@@ -473,7 +580,7 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
         *  less than the max # of CPUs. They should be ignored _iff
         *  they are physically not present.
         */
-       if (cpu_index == -1) {
+       if (pr->id == -1) {
                if (ACPI_FAILURE
                    (acpi_processor_hotadd_init(pr->handle, &pr->id))) {
                        return -ENODEV;
@@ -490,8 +597,8 @@ static int acpi_processor_get_info(struct acpi_processor *pr)
                            object.processor.pblk_length);
        else {
                pr->throttling.address = object.processor.pblk_address;
-               pr->throttling.duty_offset = acpi_fadt.duty_offset;
-               pr->throttling.duty_width = acpi_fadt.duty_width;
+               pr->throttling.duty_offset = acpi_gbl_FADT.duty_offset;
+               pr->throttling.duty_width = acpi_gbl_FADT.duty_width;
 
                pr->pblk = object.processor.pblk_address;
 
@@ -525,7 +632,7 @@ static int __cpuinit acpi_processor_start(struct acpi_device *device)
 
        pr = acpi_driver_data(device);
 
-       result = acpi_processor_get_info(pr);
+       result = acpi_processor_get_info(pr, device->flags.unique_id);
        if (result) {
                /* Processor is physically not present */
                return 0;
@@ -707,7 +814,7 @@ int acpi_processor_device_add(acpi_handle handle, struct acpi_device **device)
                return -ENODEV;
 
        if ((pr->id >= 0) && (pr->id < NR_CPUS)) {
-               kobject_uevent(&(*device)->kobj, KOBJ_ONLINE);
+               kobject_uevent(&(*device)->dev.kobj, KOBJ_ONLINE);
        }
        return 0;
 }
@@ -745,13 +852,13 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
                }
 
                if (pr->id >= 0 && (pr->id < NR_CPUS)) {
-                       kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+                       kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
                        break;
                }
 
                result = acpi_processor_start(device);
                if ((!result) && ((pr->id >= 0) && (pr->id < NR_CPUS))) {
-                       kobject_uevent(&device->kobj, KOBJ_ONLINE);
+                       kobject_uevent(&device->dev.kobj, KOBJ_ONLINE);
                } else {
                        printk(KERN_ERR PREFIX "Device [%s] failed to start\n",
                                    acpi_device_bid(device));
@@ -774,7 +881,7 @@ acpi_processor_hotplug_notify(acpi_handle handle, u32 event, void *data)
                }
 
                if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
-                       kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+                       kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
                break;
        default:
                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
@@ -895,6 +1002,12 @@ static int __init acpi_processor_init(void)
        memset(&processors, 0, sizeof(processors));
        memset(&errata, 0, sizeof(errata));
 
+#ifdef CONFIG_SMP
+       if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
+                               (struct acpi_table_header **)&madt)))
+               madt = 0;
+#endif
+
        acpi_processor_dir = proc_mkdir(ACPI_PROCESSOR_CLASS, acpi_root_dir);
        if (!acpi_processor_dir)
                return -ENOMEM;
index 3f30af2..6c6751b 100644 (file)
@@ -160,7 +160,7 @@ static inline u32 ticks_elapsed(u32 t1, u32 t2)
 {
        if (t2 >= t1)
                return (t2 - t1);
-       else if (!acpi_fadt.tmr_val_ext)
+       else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))
                return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
        else
                return ((0xFFFFFFFF - t1) + t2);
@@ -187,8 +187,7 @@ acpi_processor_power_activate(struct acpi_processor *pr,
                case ACPI_STATE_C3:
                        /* Disable bus master reload */
                        if (new->type != ACPI_STATE_C3 && pr->flags.bm_check)
-                               acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0,
-                                                 ACPI_MTX_DO_NOT_LOCK);
+                               acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
                        break;
                }
        }
@@ -198,8 +197,7 @@ acpi_processor_power_activate(struct acpi_processor *pr,
        case ACPI_STATE_C3:
                /* Enable bus master reload */
                if (old->type != ACPI_STATE_C3 && pr->flags.bm_check)
-                       acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1,
-                                         ACPI_MTX_DO_NOT_LOCK);
+                       acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1);
                break;
        }
 
@@ -236,7 +234,7 @@ static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
                /* Dummy wait op - must do something useless after P_LVL2 read
                   because chipsets cannot guarantee that STPCLK# signal
                   gets asserted in time to freeze execution properly. */
-               unused = inl(acpi_fadt.xpm_tmr_blk.address);
+               unused = inl(acpi_gbl_FADT.xpm_timer_block.address);
        }
 }
 
@@ -291,12 +289,10 @@ static void acpi_processor_idle(void)
 
                pr->power.bm_activity <<= diff;
 
-               acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS,
-                                 &bm_status, ACPI_MTX_DO_NOT_LOCK);
+               acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS, &bm_status);
                if (bm_status) {
                        pr->power.bm_activity |= 0x1;
-                       acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS,
-                                         1, ACPI_MTX_DO_NOT_LOCK);
+                       acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS, 1);
                }
                /*
                 * PIIX4 Erratum #18: Note that BM_STS doesn't always reflect
@@ -338,7 +334,7 @@ static void acpi_processor_idle(void)
         * detection phase, to work cleanly with logical CPU hotplug.
         */
        if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) && 
-           !pr->flags.has_cst && !acpi_fadt.plvl2_up)
+           !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
                cx = &pr->power.states[ACPI_STATE_C1];
 #endif
 
@@ -384,11 +380,11 @@ static void acpi_processor_idle(void)
 
        case ACPI_STATE_C2:
                /* Get start time (ticks) */
-               t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+               t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
                /* Invoke C2 */
                acpi_cstate_enter(cx);
                /* Get end time (ticks) */
-               t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+               t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 
 #ifdef CONFIG_GENERIC_TIME
                /* TSC halts in C2, so notify users */
@@ -411,8 +407,7 @@ static void acpi_processor_idle(void)
                                 * All CPUs are trying to go to C3
                                 * Disable bus master arbitration
                                 */
-                               acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
-                                                 ACPI_MTX_DO_NOT_LOCK);
+                               acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
                        }
                } else {
                        /* SMP with no shared cache... Invalidate cache  */
@@ -420,16 +415,15 @@ static void acpi_processor_idle(void)
                }
 
                /* Get start time (ticks) */
-               t1 = inl(acpi_fadt.xpm_tmr_blk.address);
+               t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
                /* Invoke C3 */
                acpi_cstate_enter(cx);
                /* Get end time (ticks) */
-               t2 = inl(acpi_fadt.xpm_tmr_blk.address);
+               t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
                if (pr->flags.bm_check) {
                        /* Enable bus master arbitration */
                        atomic_dec(&c3_cpu_count);
-                       acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0,
-                                         ACPI_MTX_DO_NOT_LOCK);
+                       acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
                }
 
 #ifdef CONFIG_GENERIC_TIME
@@ -457,7 +451,7 @@ static void acpi_processor_idle(void)
 #ifdef CONFIG_HOTPLUG_CPU
        /* Don't do promotion/demotion */
        if ((cx->type == ACPI_STATE_C1) && (num_online_cpus() > 1) &&
-           !pr->flags.has_cst && !acpi_fadt.plvl2_up) {
+           !pr->flags.has_cst && !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED)) {
                next_state = cx;
                goto end;
        }
@@ -627,7 +621,8 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
         * Check for P_LVL2_UP flag before entering C2 and above on
         * an SMP system. 
         */
-       if ((num_online_cpus() > 1) && !acpi_fadt.plvl2_up)
+       if ((num_online_cpus() > 1) &&
+           !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
                return -ENODEV;
 #endif
 
@@ -636,8 +631,8 @@ static int acpi_processor_get_power_info_fadt(struct acpi_processor *pr)
        pr->power.states[ACPI_STATE_C3].address = pr->pblk + 5;
 
        /* determine latencies from FADT */
-       pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat;
-       pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat;
+       pr->power.states[ACPI_STATE_C2].latency = acpi_gbl_FADT.C2latency;
+       pr->power.states[ACPI_STATE_C3].latency = acpi_gbl_FADT.C3latency;
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                          "lvl2[0x%08x] lvl3[0x%08x]\n",
@@ -883,14 +878,13 @@ static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
                 * WBINVD should be set in fadt, for C3 state to be
                 * supported on when bm_check is not required.
                 */
-               if (acpi_fadt.wb_invd != 1) {
+               if (!(acpi_gbl_FADT.flags & ACPI_FADT_WBINVD)) {
                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
                                          "Cache invalidation should work properly"
                                          " for C3 to be enabled on SMP systems\n"));
                        return;
                }
-               acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD,
-                                 0, ACPI_MTX_DO_NOT_LOCK);
+               acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0);
        }
 
        /*
@@ -1096,7 +1090,7 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
                seq_printf(seq, "latency[%03d] usage[%08d] duration[%020llu]\n",
                           pr->power.states[i].latency,
                           pr->power.states[i].usage,
-                          pr->power.states[i].time);
+                          (unsigned long long)pr->power.states[i].time);
        }
 
       end:
@@ -1164,9 +1158,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
        if (!pr)
                return -EINVAL;
 
-       if (acpi_fadt.cst_cnt && !nocst) {
+       if (acpi_gbl_FADT.cst_control && !nocst) {
                status =
-                   acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8);
+                   acpi_os_write_port(acpi_gbl_FADT.smi_command, acpi_gbl_FADT.cst_control, 8);
                if (ACPI_FAILURE(status)) {
                        ACPI_EXCEPTION((AE_INFO, status,
                                        "Notifying BIOS of _CST ability failed"));
index cbb6f08..058f13c 100644 (file)
@@ -352,31 +352,24 @@ int acpi_processor_notify_smm(struct module *calling_module)
 
        is_done = -EIO;
 
-       /* Can't write pstate_cnt to smi_cmd if either value is zero */
-       if ((!acpi_fadt.smi_cmd) || (!acpi_fadt.pstate_cnt)) {
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_cnt\n"));
+       /* Can't write pstate_control to smi_command if either value is zero */
+       if ((!acpi_gbl_FADT.smi_command) || (!acpi_gbl_FADT.pstate_control)) {
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No SMI port or pstate_control\n"));
                module_put(calling_module);
                return 0;
        }
 
        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                         "Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n",
-                         acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd));
+                         "Writing pstate_control [0x%x] to smi_command [0x%x]\n",
+                         acpi_gbl_FADT.pstate_control, acpi_gbl_FADT.smi_command));
 
-       /* FADT v1 doesn't support pstate_cnt, many BIOS vendors use
-        * it anyway, so we need to support it... */
-       if (acpi_fadt_is_v1) {
-               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                 "Using v1.0 FADT reserved value for pstate_cnt\n"));
-       }
-
-       status = acpi_os_write_port(acpi_fadt.smi_cmd,
-                                   (u32) acpi_fadt.pstate_cnt, 8);
+       status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
+                                   (u32) acpi_gbl_FADT.pstate_control, 8);
        if (ACPI_FAILURE(status)) {
                ACPI_EXCEPTION((AE_INFO, status,
-                               "Failed to write pstate_cnt [0x%x] to "
-                               "smi_cmd [0x%x]", acpi_fadt.pstate_cnt,
-                               acpi_fadt.smi_cmd));
+                               "Failed to write pstate_control [0x%x] to "
+                               "smi_command [0x%x]", acpi_gbl_FADT.pstate_control,
+                               acpi_gbl_FADT.smi_command));
                module_put(calling_module);
                return status;
        }
index 0ec7dcd..89dff36 100644 (file)
@@ -125,7 +125,7 @@ int acpi_processor_set_throttling(struct acpi_processor *pr, int state)
                /* Used to clear all duty_value bits */
                duty_mask = pr->throttling.state_count - 1;
 
-               duty_mask <<= acpi_fadt.duty_offset;
+               duty_mask <<= acpi_gbl_FADT.duty_offset;
                duty_mask = ~duty_mask;
        }
 
@@ -208,7 +208,7 @@ int acpi_processor_get_throttling_info(struct acpi_processor *pr)
                return 0;
        }
 
-       pr->throttling.state_count = 1 << acpi_fadt.duty_width;
+       pr->throttling.state_count = 1 << acpi_gbl_FADT.duty_width;
 
        /*
         * Compute state values. Note that throttling displays a linear power/
index 8fa3213..271e615 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cf87b02..8c6d3fd 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 008058a..1358c06 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9c99a72..de20a5d 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9e7ae2f..7e3c335 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ea56716..b297bc3 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1fa63bc..5657f7b 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 29423ce..a92755c 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a513193..521eab7 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index faf6e10..3b63b56 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a9cbee8..2442a8f 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1999e2a..991f890 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 283d875..64f26db 100644 (file)
@@ -21,101 +21,305 @@ extern struct acpi_device *acpi_root;
 #define ACPI_BUS_DEVICE_NAME           "System Bus"
 
 static LIST_HEAD(acpi_device_list);
+static LIST_HEAD(acpi_bus_id_list);
 DEFINE_SPINLOCK(acpi_device_lock);
 LIST_HEAD(acpi_wakeup_device_list);
 
+struct acpi_device_bus_id{
+       char bus_id[15];
+       unsigned int instance_no;
+       struct list_head node;
+};
+static int acpi_eject_operation(acpi_handle handle, int lockable)
+{
+       struct acpi_object_list arg_list;
+       union acpi_object arg;
+       acpi_status status = AE_OK;
+
+       /*
+        * TBD: evaluate _PS3?
+        */
+
+       if (lockable) {
+               arg_list.count = 1;
+               arg_list.pointer = &arg;
+               arg.type = ACPI_TYPE_INTEGER;
+               arg.integer.value = 0;
+               acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
+       }
 
-static void acpi_device_release(struct kobject *kobj)
+       arg_list.count = 1;
+       arg_list.pointer = &arg;
+       arg.type = ACPI_TYPE_INTEGER;
+       arg.integer.value = 1;
+
+       /*
+        * TBD: _EJD support.
+        */
+
+       status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
+       if (ACPI_FAILURE(status)) {
+               return (-ENODEV);
+       }
+
+       return (0);
+}
+
+static ssize_t
+acpi_eject_store(struct device *d, struct device_attribute *attr,
+               const char *buf, size_t count)
 {
-       struct acpi_device *dev = container_of(kobj, struct acpi_device, kobj);
-       kfree(dev->pnp.cid_list);
-       kfree(dev);
+       int result;
+       int ret = count;
+       int islockable;
+       acpi_status status;
+       acpi_handle handle;
+       acpi_object_type type = 0;
+       struct acpi_device *acpi_device = to_acpi_device(d);
+
+       if ((!count) || (buf[0] != '1')) {
+               return -EINVAL;
+       }
+#ifndef FORCE_EJECT
+       if (acpi_device->driver == NULL) {
+               ret = -ENODEV;
+               goto err;
+       }
+#endif
+       status = acpi_get_type(acpi_device->handle, &type);
+       if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
+               ret = -ENODEV;
+               goto err;
+       }
+
+       islockable = acpi_device->flags.lockable;
+       handle = acpi_device->handle;
+
+       result = acpi_bus_trim(acpi_device, 1);
+
+       if (!result)
+               result = acpi_eject_operation(handle, islockable);
+
+       if (result) {
+               ret = -EBUSY;
+       }
+      err:
+       return ret;
 }
 
-struct acpi_device_attribute {
-       struct attribute attr;
-        ssize_t(*show) (struct acpi_device *, char *);
-        ssize_t(*store) (struct acpi_device *, const char *, size_t);
-};
+static DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
 
-typedef void acpi_device_sysfs_files(struct kobject *,
-                                    const struct attribute *);
+static ssize_t
+acpi_device_hid_show(struct device *dev, struct device_attribute *attr, char *buf) {
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
 
-static void setup_sys_fs_device_files(struct acpi_device *dev,
-                                     acpi_device_sysfs_files * func);
+       return sprintf(buf, "%s\n", acpi_dev->pnp.hardware_id);
+}
+static DEVICE_ATTR(hid, 0444, acpi_device_hid_show, NULL);
 
-#define create_sysfs_device_files(dev) \
-       setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_create_file)
-#define remove_sysfs_device_files(dev) \
-       setup_sys_fs_device_files(dev, (acpi_device_sysfs_files *)&sysfs_remove_file)
+static ssize_t
+acpi_device_path_show(struct device *dev, struct device_attribute *attr, char *buf) {
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       struct acpi_buffer path = {ACPI_ALLOCATE_BUFFER, NULL};
+       int result;
 
-#define to_acpi_device(n) container_of(n, struct acpi_device, kobj)
-#define to_handle_attr(n) container_of(n, struct acpi_device_attribute, attr);
+       result = acpi_get_name(acpi_dev->handle, ACPI_FULL_PATHNAME, &path);
+       if(result)
+               goto end;
 
-static ssize_t acpi_device_attr_show(struct kobject *kobj,
-                                    struct attribute *attr, char *buf)
+       result = sprintf(buf, "%s\n", (char*)path.pointer);
+       kfree(path.pointer);
+  end:
+       return result;
+}
+static DEVICE_ATTR(path, 0444, acpi_device_path_show, NULL);
+
+static int acpi_device_setup_files(struct acpi_device *dev)
+{
+       acpi_status status;
+       acpi_handle temp;
+       int result = 0;
+
+       /*
+        * Devices gotten from FADT don't have a "path" attribute
+        */
+       if(dev->handle) {
+               result = device_create_file(&dev->dev, &dev_attr_path);
+               if(result)
+                       goto end;
+       }
+
+       if(dev->flags.hardware_id) {
+               result = device_create_file(&dev->dev, &dev_attr_hid);
+               if(result)
+                       goto end;
+       }
+
+        /*
+         * If device has _EJ0, 'eject' file is created that is used to trigger
+         * hot-removal function from userland.
+         */
+       status = acpi_get_handle(dev->handle, "_EJ0", &temp);
+       if (ACPI_SUCCESS(status))
+               result = device_create_file(&dev->dev, &dev_attr_eject);
+  end:
+       return result;
+}
+
+static void acpi_device_remove_files(struct acpi_device *dev)
 {
-       struct acpi_device *device = to_acpi_device(kobj);
-       struct acpi_device_attribute *attribute = to_handle_attr(attr);
-       return attribute->show ? attribute->show(device, buf) : -EIO;
+       acpi_status status;
+       acpi_handle temp;
+
+       /*
+        * If device has _EJ0, 'eject' file is created that is used to trigger
+        * hot-removal function from userland.
+        */
+       status = acpi_get_handle(dev->handle, "_EJ0", &temp);
+       if (ACPI_SUCCESS(status))
+               device_remove_file(&dev->dev, &dev_attr_eject);
+
+       if(dev->flags.hardware_id)
+               device_remove_file(&dev->dev, &dev_attr_hid);
+       if(dev->handle)
+               device_remove_file(&dev->dev, &dev_attr_path);
 }
-static ssize_t acpi_device_attr_store(struct kobject *kobj,
-                                     struct attribute *attr, const char *buf,
-                                     size_t len)
+/* --------------------------------------------------------------------------
+                       ACPI Bus operations
+   -------------------------------------------------------------------------- */
+static void acpi_device_release(struct device *dev)
 {
-       struct acpi_device *device = to_acpi_device(kobj);
-       struct acpi_device_attribute *attribute = to_handle_attr(attr);
-       return attribute->store ? attribute->store(device, buf, len) : -EIO;
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+
+       kfree(acpi_dev->pnp.cid_list);
+       kfree(acpi_dev);
 }
 
-static struct sysfs_ops acpi_device_sysfs_ops = {
-       .show = acpi_device_attr_show,
-       .store = acpi_device_attr_store,
-};
+static int acpi_device_suspend(struct device *dev, pm_message_t state)
+{
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       struct acpi_driver *acpi_drv = acpi_dev->driver;
 
-static struct kobj_type ktype_acpi_ns = {
-       .sysfs_ops = &acpi_device_sysfs_ops,
-       .release = acpi_device_release,
-};
+       if (acpi_drv && acpi_drv->ops.suspend)
+               return acpi_drv->ops.suspend(acpi_dev, state);
+       return 0;
+}
 
-static int namespace_uevent(struct kset *kset, struct kobject *kobj,
-                            char **envp, int num_envp, char *buffer,
-                            int buffer_size)
+static int acpi_device_resume(struct device *dev)
 {
-       struct acpi_device *dev = to_acpi_device(kobj);
-       int i = 0;
-       int len = 0;
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       struct acpi_driver *acpi_drv = acpi_dev->driver;
 
-       if (!dev->driver)
-               return 0;
+       if (acpi_drv && acpi_drv->ops.resume)
+               return acpi_drv->ops.resume(acpi_dev);
+       return 0;
+}
 
-       if (add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &len,
-                          "PHYSDEVDRIVER=%s", dev->driver->name))
+static int acpi_bus_match(struct device *dev, struct device_driver *drv)
+{
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       struct acpi_driver *acpi_drv = to_acpi_driver(drv);
+
+       return !acpi_match_ids(acpi_dev, acpi_drv->ids);
+}
+
+static int acpi_device_uevent(struct device *dev, char **envp, int num_envp,
+       char *buffer, int buffer_size)
+{
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       int i = 0, length = 0, ret = 0;
+
+       if (acpi_dev->flags.hardware_id)
+               ret = add_uevent_var(envp, num_envp, &i,
+                       buffer, buffer_size, &length,
+                       "HWID=%s", acpi_dev->pnp.hardware_id);
+       if (ret)
                return -ENOMEM;
+       if (acpi_dev->flags.compatible_ids) {
+               int j;
+               struct acpi_compatible_id_list *cid_list;
+
+               cid_list = acpi_dev->pnp.cid_list;
+
+               for (j = 0; j < cid_list->count; j++) {
+                       ret = add_uevent_var(envp, num_envp, &i, buffer,
+                               buffer_size, &length, "COMPTID=%s",
+                               cid_list->id[j].value);
+                       if (ret)
+                               return -ENOMEM;
+               }
+       }
 
        envp[i] = NULL;
+       return 0;
+}
+
+static int acpi_bus_driver_init(struct acpi_device *, struct acpi_driver *);
+static int acpi_start_single_object(struct acpi_device *);
+static int acpi_device_probe(struct device * dev)
+{
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       struct acpi_driver *acpi_drv = to_acpi_driver(dev->driver);
+       int ret;
+
+       ret = acpi_bus_driver_init(acpi_dev, acpi_drv);
+       if (!ret) {
+               if (acpi_dev->bus_ops.acpi_op_start)
+                       acpi_start_single_object(acpi_dev);
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                       "Found driver [%s] for device [%s]\n",
+                       acpi_drv->name, acpi_dev->pnp.bus_id));
+               get_device(dev);
+       }
+       return ret;
+}
 
+static int acpi_device_remove(struct device * dev)
+{
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       struct acpi_driver *acpi_drv = acpi_dev->driver;
+
+       if (acpi_drv) {
+               if (acpi_drv->ops.stop)
+                       acpi_drv->ops.stop(acpi_dev, acpi_dev->removal_type);
+               if (acpi_drv->ops.remove)
+                       acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
+       }
+       acpi_dev->driver = NULL;
+       acpi_driver_data(dev) = NULL;
+
+       put_device(dev);
        return 0;
 }
 
-static struct kset_uevent_ops namespace_uevent_ops = {
-       .uevent = &namespace_uevent,
-};
+static void acpi_device_shutdown(struct device *dev)
+{
+       struct acpi_device *acpi_dev = to_acpi_device(dev);
+       struct acpi_driver *acpi_drv = acpi_dev->driver;
 
-static struct kset acpi_namespace_kset = {
-       .kobj = {
-                .name = "namespace",
-                },
-       .subsys = &acpi_subsys,
-       .ktype = &ktype_acpi_ns,
-       .uevent_ops = &namespace_uevent_ops,
+       if (acpi_drv && acpi_drv->ops.shutdown)
+               acpi_drv->ops.shutdown(acpi_dev);
+
+       return ;
+}
+
+static struct bus_type acpi_bus_type = {
+       .name           = "acpi",
+       .suspend        = acpi_device_suspend,
+       .resume         = acpi_device_resume,
+       .shutdown       = acpi_device_shutdown,
+       .match          = acpi_bus_match,
+       .probe          = acpi_device_probe,
+       .remove         = acpi_device_remove,
+       .uevent         = acpi_device_uevent,
 };
 
-static void acpi_device_register(struct acpi_device *device,
+static int acpi_device_register(struct acpi_device *device,
                                 struct acpi_device *parent)
 {
-       int err;
-
+       int result;
+       struct acpi_device_bus_id *acpi_device_bus_id, *new_bus_id;
+       int found = 0;
        /*
         * Linkage
         * -------
@@ -126,7 +330,33 @@ static void acpi_device_register(struct acpi_device *device,
        INIT_LIST_HEAD(&device->g_list);
        INIT_LIST_HEAD(&device->wakeup_list);
 
+       new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
+       if (!new_bus_id) {
+               printk(KERN_ERR PREFIX "Memory allocation error\n");
+               return -ENOMEM;
+       }
+
        spin_lock(&acpi_device_lock);
+       /*
+        * Find suitable bus_id and instance number in acpi_bus_id_list
+        * If failed, create one and link it into acpi_bus_id_list
+        */
+       list_for_each_entry(acpi_device_bus_id, &acpi_bus_id_list, node) {
+               if(!strcmp(acpi_device_bus_id->bus_id, device->flags.hardware_id? device->pnp.hardware_id : "device")) {
+                       acpi_device_bus_id->instance_no ++;
+                       found = 1;
+                       kfree(new_bus_id);
+                       break;
+               }
+       }
+       if(!found) {
+               acpi_device_bus_id = new_bus_id;
+               strcpy(acpi_device_bus_id->bus_id, device->flags.hardware_id ? device->pnp.hardware_id : "device");
+               acpi_device_bus_id->instance_no = 0;
+               list_add_tail(&acpi_device_bus_id->node, &acpi_bus_id_list);
+       }
+       sprintf(device->dev.bus_id, "%s:%02x", acpi_device_bus_id->bus_id, acpi_device_bus_id->instance_no);
+
        if (device->parent) {
                list_add_tail(&device->node, &device->parent->children);
                list_add_tail(&device->g_list, &device->parent->g_list);
@@ -136,16 +366,33 @@ static void acpi_device_register(struct acpi_device *device,
                list_add_tail(&device->wakeup_list, &acpi_wakeup_device_list);
        spin_unlock(&acpi_device_lock);
 
-       strlcpy(device->kobj.name, device->pnp.bus_id, KOBJ_NAME_LEN);
-       if (parent)
-               device->kobj.parent = &parent->kobj;
-       device->kobj.ktype = &ktype_acpi_ns;
-       device->kobj.kset = &acpi_namespace_kset;
-       err = kobject_register(&device->kobj);
-       if (err < 0)
-               printk(KERN_WARNING "%s: kobject_register error: %d\n",
-                       __FUNCTION__, err);
-       create_sysfs_device_files(device);
+       if (device->parent)
+               device->dev.parent = &parent->dev;
+       device->dev.bus = &acpi_bus_type;
+       device_initialize(&device->dev);
+       device->dev.release = &acpi_device_release;
+       result = device_add(&device->dev);
+       if(result) {
+               printk("Error adding device %s", device->dev.bus_id);
+               goto end;
+       }
+
+       result = acpi_device_setup_files(device);
+       if(result)
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error creating sysfs interface for device %s\n", device->dev.bus_id));
+
+       device->removal_type = ACPI_BUS_REMOVAL_NORMAL;
+       return 0;
+  end:
+       spin_lock(&acpi_device_lock);
+       if (device->parent) {
+               list_del(&device->node);
+               list_del(&device->g_list);
+       } else
+               list_del(&device->g_list);
+       list_del(&device->wakeup_list);
+       spin_unlock(&acpi_device_lock);
+       return result;
 }
 
 static void acpi_device_unregister(struct acpi_device *device, int type)
@@ -158,81 +405,143 @@ static void acpi_device_unregister(struct acpi_device *device, int type)
                list_del(&device->g_list);
 
        list_del(&device->wakeup_list);
-
        spin_unlock(&acpi_device_lock);
 
        acpi_detach_data(device->handle, acpi_bus_data_handler);
-       remove_sysfs_device_files(device);
-       kobject_unregister(&device->kobj);
+
+       acpi_device_remove_files(device);
+       device_unregister(&device->dev);
 }
 
-void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
+/* --------------------------------------------------------------------------
+                                 Driver Management
+   -------------------------------------------------------------------------- */
+/**
+ * acpi_bus_driver_init - add a device to a driver
+ * @device: the device to add and initialize
+ * @driver: driver for the device
+ *
+ * Used to initialize a device via its device driver.  Called whenever a 
+ * driver is bound to a device.  Invokes the driver's add() ops.
+ */
+static int
+acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
 {
+       int result = 0;
 
-       /* TBD */
 
-       return;
-}
+       if (!device || !driver)
+               return -EINVAL;
 
-static int acpi_bus_get_power_flags(struct acpi_device *device)
-{
-       acpi_status status = 0;
-       acpi_handle handle = NULL;
-       u32 i = 0;
+       if (!driver->ops.add)
+               return -ENOSYS;
 
+       result = driver->ops.add(device);
+       if (result) {
+               device->driver = NULL;
+               acpi_driver_data(device) = NULL;
+               return result;
+       }
 
-       /*
-        * Power Management Flags
-        */
-       status = acpi_get_handle(device->handle, "_PSC", &handle);
-       if (ACPI_SUCCESS(status))
-               device->power.flags.explicit_get = 1;
-       status = acpi_get_handle(device->handle, "_IRC", &handle);
-       if (ACPI_SUCCESS(status))
-               device->power.flags.inrush_current = 1;
+       device->driver = driver;
 
        /*
-        * Enumerate supported power management states
+        * TBD - Configuration Management: Assign resources to device based
+        * upon possible configuration and currently allocated resources.
         */
-       for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
-               struct acpi_device_power_state *ps = &device->power.states[i];
-               char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
 
-               /* Evaluate "_PRx" to se if power resources are referenced */
-               acpi_evaluate_reference(device->handle, object_name, NULL,
-                                       &ps->resources);
-               if (ps->resources.count) {
-                       device->power.flags.power_resources = 1;
-                       ps->flags.valid = 1;
-               }
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+                         "Driver successfully bound to device\n"));
+       return 0;
+}
 
-               /* Evaluate "_PSx" to see if we can do explicit sets */
-               object_name[2] = 'S';
-               status = acpi_get_handle(device->handle, object_name, &handle);
-               if (ACPI_SUCCESS(status)) {
-                       ps->flags.explicit_set = 1;
-                       ps->flags.valid = 1;
-               }
+static int acpi_start_single_object(struct acpi_device *device)
+{
+       int result = 0;
+       struct acpi_driver *driver;
+
+
+       if (!(driver = device->driver))
+               return 0;
+
+       if (driver->ops.start) {
+               result = driver->ops.start(device);
+               if (result && driver->ops.remove)
+                       driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
+       }
+
+       return result;
+}
+
+/**
+ * acpi_bus_register_driver - register a driver with the ACPI bus
+ * @driver: driver being registered
+ *
+ * Registers a driver with the ACPI bus.  Searches the namespace for all
+ * devices that match the driver's criteria and binds.  Returns zero for
+ * success or a negative error status for failure.
+ */
+int acpi_bus_register_driver(struct acpi_driver *driver)
+{
+       int ret;
+
+       if (acpi_disabled)
+               return -ENODEV;
+       driver->drv.name = driver->name;
+       driver->drv.bus = &acpi_bus_type;
+       driver->drv.owner = driver->owner;
+
+       ret = driver_register(&driver->drv);
+       return ret;
+}
+
+EXPORT_SYMBOL(acpi_bus_register_driver);
+
+/**
+ * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
+ * @driver: driver to unregister
+ *
+ * Unregisters a driver with the ACPI bus.  Searches the namespace for all
+ * devices that match the driver's criteria and unbinds.
+ */
+void acpi_bus_unregister_driver(struct acpi_driver *driver)
+{
+       driver_unregister(&driver->drv);
+}
+
+EXPORT_SYMBOL(acpi_bus_unregister_driver);
+
+/* --------------------------------------------------------------------------
+                                 Device Enumeration
+   -------------------------------------------------------------------------- */
+acpi_status
+acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
+{
+       acpi_status status;
+       acpi_handle tmp;
+       struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object *obj;
 
-               /* State is valid if we have some power control */
-               if (ps->resources.count || ps->flags.explicit_set)
-                       ps->flags.valid = 1;
+       status = acpi_get_handle(handle, "_EJD", &tmp);
+       if (ACPI_FAILURE(status))
+               return status;
 
-               ps->power = -1; /* Unknown - driver assigned */
-               ps->latency = -1;       /* Unknown - driver assigned */
+       status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
+       if (ACPI_SUCCESS(status)) {
+               obj = buffer.pointer;
+               status = acpi_get_handle(NULL, obj->string.pointer, ejd);
+               kfree(buffer.pointer);
        }
+       return status;
+}
+EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
 
-       /* Set defaults for D0 and D3 states (always valid) */
-       device->power.states[ACPI_STATE_D0].flags.valid = 1;
-       device->power.states[ACPI_STATE_D0].power = 100;
-       device->power.states[ACPI_STATE_D3].flags.valid = 1;
-       device->power.states[ACPI_STATE_D3].power = 0;
-
-       /* TBD: System wake support and resource requirements. */
+void acpi_bus_data_handler(acpi_handle handle, u32 function, void *context)
+{
 
-       device->power.state = ACPI_STATE_UNKNOWN;
+       /* TBD */
 
-       return 0;
+       return;
 }
 
 int acpi_match_ids(struct acpi_device *device, char *ids)
@@ -254,6 +563,12 @@ int acpi_match_ids(struct acpi_device *device, char *ids)
        return -ENOENT;
 }
 
+static int acpi_bus_get_perf_flags(struct acpi_device *device)
+{
+       device->performance.state = ACPI_STATE_UNKNOWN;
+       return 0;
+}
+
 static acpi_status
 acpi_bus_extract_wakeup_device_power_package(struct acpi_device *device,
                                             union acpi_object *package)
@@ -327,370 +642,77 @@ static int acpi_bus_get_wakeup_device_flags(struct acpi_device *device)
 
        kfree(buffer.pointer);
 
-       device->wakeup.flags.valid = 1;
-       /* Power button, Lid switch always enable wakeup */
-       if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E"))
-               device->wakeup.flags.run_wake = 1;
-
-      end:
-       if (ACPI_FAILURE(status))
-               device->flags.wake_capable = 0;
-       return 0;
-}
-
-/* --------------------------------------------------------------------------
-               ACPI sysfs device file support
-   -------------------------------------------------------------------------- */
-static ssize_t acpi_eject_store(struct acpi_device *device,
-                               const char *buf, size_t count);
-
-#define ACPI_DEVICE_ATTR(_name,_mode,_show,_store) \
-static struct acpi_device_attribute acpi_device_attr_##_name = \
-               __ATTR(_name, _mode, _show, _store)
-
-ACPI_DEVICE_ATTR(eject, 0200, NULL, acpi_eject_store);
-
-/**
- * setup_sys_fs_device_files - sets up the device files under device namespace
- * @dev:       acpi_device object
- * @func:      function pointer to create or destroy the device file
- */
-static void
-setup_sys_fs_device_files(struct acpi_device *dev,
-                         acpi_device_sysfs_files * func)
-{
-       acpi_status status;
-       acpi_handle temp = NULL;
-
-       /*
-        * If device has _EJ0, 'eject' file is created that is used to trigger
-        * hot-removal function from userland.
-        */
-       status = acpi_get_handle(dev->handle, "_EJ0", &temp);
-       if (ACPI_SUCCESS(status))
-               (*(func)) (&dev->kobj, &acpi_device_attr_eject.attr);
-}
-
-static int acpi_eject_operation(acpi_handle handle, int lockable)
-{
-       struct acpi_object_list arg_list;
-       union acpi_object arg;
-       acpi_status status = AE_OK;
-
-       /*
-        * TBD: evaluate _PS3?
-        */
-
-       if (lockable) {
-               arg_list.count = 1;
-               arg_list.pointer = &arg;
-               arg.type = ACPI_TYPE_INTEGER;
-               arg.integer.value = 0;
-               acpi_evaluate_object(handle, "_LCK", &arg_list, NULL);
-       }
-
-       arg_list.count = 1;
-       arg_list.pointer = &arg;
-       arg.type = ACPI_TYPE_INTEGER;
-       arg.integer.value = 1;
-
-       /*
-        * TBD: _EJD support.
-        */
-
-       status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
-       if (ACPI_FAILURE(status)) {
-               return (-ENODEV);
-       }
-
-       return (0);
-}
-
-static ssize_t
-acpi_eject_store(struct acpi_device *device, const char *buf, size_t count)
-{
-       int result;
-       int ret = count;
-       int islockable;
-       acpi_status status;
-       acpi_handle handle;
-       acpi_object_type type = 0;
-
-       if ((!count) || (buf[0] != '1')) {
-               return -EINVAL;
-       }
-#ifndef FORCE_EJECT
-       if (device->driver == NULL) {
-               ret = -ENODEV;
-               goto err;
-       }
-#endif
-       status = acpi_get_type(device->handle, &type);
-       if (ACPI_FAILURE(status) || (!device->flags.ejectable)) {
-               ret = -ENODEV;
-               goto err;
-       }
-
-       islockable = device->flags.lockable;
-       handle = device->handle;
-
-       result = acpi_bus_trim(device, 1);
-
-       if (!result)
-               result = acpi_eject_operation(handle, islockable);
-
-       if (result) {
-               ret = -EBUSY;
-       }
-      err:
-       return ret;
-}
-
-/* --------------------------------------------------------------------------
-                              Performance Management
-   -------------------------------------------------------------------------- */
-
-static int acpi_bus_get_perf_flags(struct acpi_device *device)
-{
-       device->performance.state = ACPI_STATE_UNKNOWN;
-       return 0;
-}
-
-/* --------------------------------------------------------------------------
-                                 Driver Management
-   -------------------------------------------------------------------------- */
-
-static LIST_HEAD(acpi_bus_drivers);
-
-/**
- * acpi_bus_match - match device IDs to driver's supported IDs
- * @device: the device that we are trying to match to a driver
- * @driver: driver whose device id table is being checked
- *
- * Checks the device's hardware (_HID) or compatible (_CID) ids to see if it
- * matches the specified driver's criteria.
- */
-static int
-acpi_bus_match(struct acpi_device *device, struct acpi_driver *driver)
-{
-       if (driver && driver->ops.match)
-               return driver->ops.match(device, driver);
-       return acpi_match_ids(device, driver->ids);
-}
-
-/**
- * acpi_bus_driver_init - add a device to a driver
- * @device: the device to add and initialize
- * @driver: driver for the device
- *
- * Used to initialize a device via its device driver.  Called whenever a 
- * driver is bound to a device.  Invokes the driver's add() and start() ops.
- */
-static int
-acpi_bus_driver_init(struct acpi_device *device, struct acpi_driver *driver)
-{
-       int result = 0;
-
-
-       if (!device || !driver)
-               return -EINVAL;
-
-       if (!driver->ops.add)
-               return -ENOSYS;
-
-       result = driver->ops.add(device);
-       if (result) {
-               device->driver = NULL;
-               acpi_driver_data(device) = NULL;
-               return result;
-       }
-
-       device->driver = driver;
-
-       /*
-        * TBD - Configuration Management: Assign resources to device based
-        * upon possible configuration and currently allocated resources.
-        */
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                         "Driver successfully bound to device\n"));
-       return 0;
-}
-
-static int acpi_start_single_object(struct acpi_device *device)
-{
-       int result = 0;
-       struct acpi_driver *driver;
-
-
-       if (!(driver = device->driver))
-               return 0;
-
-       if (driver->ops.start) {
-               result = driver->ops.start(device);
-               if (result && driver->ops.remove)
-                       driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
-       }
-
-       return result;
-}
-
-static void acpi_driver_attach(struct acpi_driver *drv)
-{
-       struct list_head *node, *next;
-
-
-       spin_lock(&acpi_device_lock);
-       list_for_each_safe(node, next, &acpi_device_list) {
-               struct acpi_device *dev =
-                   container_of(node, struct acpi_device, g_list);
-
-               if (dev->driver || !dev->status.present)
-                       continue;
-               spin_unlock(&acpi_device_lock);
-
-               if (!acpi_bus_match(dev, drv)) {
-                       if (!acpi_bus_driver_init(dev, drv)) {
-                               acpi_start_single_object(dev);
-                               atomic_inc(&drv->references);
-                               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                                 "Found driver [%s] for device [%s]\n",
-                                                 drv->name, dev->pnp.bus_id));
-                       }
-               }
-               spin_lock(&acpi_device_lock);
-       }
-       spin_unlock(&acpi_device_lock);
-}
-
-static void acpi_driver_detach(struct acpi_driver *drv)
-{
-       struct list_head *node, *next;
-
-
-       spin_lock(&acpi_device_lock);
-       list_for_each_safe(node, next, &acpi_device_list) {
-               struct acpi_device *dev =
-                   container_of(node, struct acpi_device, g_list);
-
-               if (dev->driver == drv) {
-                       spin_unlock(&acpi_device_lock);
-                       if (drv->ops.remove)
-                               drv->ops.remove(dev, ACPI_BUS_REMOVAL_NORMAL);
-                       spin_lock(&acpi_device_lock);
-                       dev->driver = NULL;
-                       dev->driver_data = NULL;
-                       atomic_dec(&drv->references);
-               }
-       }
-       spin_unlock(&acpi_device_lock);
-}
-
-/**
- * acpi_bus_register_driver - register a driver with the ACPI bus
- * @driver: driver being registered
- *
- * Registers a driver with the ACPI bus.  Searches the namespace for all
- * devices that match the driver's criteria and binds.  Returns zero for
- * success or a negative error status for failure.
- */
-int acpi_bus_register_driver(struct acpi_driver *driver)
-{
-
-       if (acpi_disabled)
-               return -ENODEV;
-
-       spin_lock(&acpi_device_lock);
-       list_add_tail(&driver->node, &acpi_bus_drivers);
-       spin_unlock(&acpi_device_lock);
-       acpi_driver_attach(driver);
-
+       device->wakeup.flags.valid = 1;
+       /* Power button, Lid switch always enable wakeup */
+       if (!acpi_match_ids(device, "PNP0C0D,PNP0C0C,PNP0C0E"))
+               device->wakeup.flags.run_wake = 1;
+
+      end:
+       if (ACPI_FAILURE(status))
+               device->flags.wake_capable = 0;
        return 0;
 }
 
-EXPORT_SYMBOL(acpi_bus_register_driver);
-
-/**
- * acpi_bus_unregister_driver - unregisters a driver with the APIC bus
- * @driver: driver to unregister
- *
- * Unregisters a driver with the ACPI bus.  Searches the namespace for all
- * devices that match the driver's criteria and unbinds.
- */
-void acpi_bus_unregister_driver(struct acpi_driver *driver)
+static int acpi_bus_get_power_flags(struct acpi_device *device)
 {
-       acpi_driver_detach(driver);
+       acpi_status status = 0;
+       acpi_handle handle = NULL;
+       u32 i = 0;
 
-       if (!atomic_read(&driver->references)) {
-               spin_lock(&acpi_device_lock);
-               list_del_init(&driver->node);
-               spin_unlock(&acpi_device_lock);
-       }
-       return;
-}
 
-EXPORT_SYMBOL(acpi_bus_unregister_driver);
+       /*
+        * Power Management Flags
+        */
+       status = acpi_get_handle(device->handle, "_PSC", &handle);
+       if (ACPI_SUCCESS(status))
+               device->power.flags.explicit_get = 1;
+       status = acpi_get_handle(device->handle, "_IRC", &handle);
+       if (ACPI_SUCCESS(status))
+               device->power.flags.inrush_current = 1;
 
-/**
- * acpi_bus_find_driver - check if there is a driver installed for the device
- * @device: device that we are trying to find a supporting driver for
- *
- * Parses the list of registered drivers looking for a driver applicable for
- * the specified device.
- */
-static int acpi_bus_find_driver(struct acpi_device *device)
-{
-       int result = 0;
-       struct list_head *node, *next;
+       /*
+        * Enumerate supported power management states
+        */
+       for (i = ACPI_STATE_D0; i <= ACPI_STATE_D3; i++) {
+               struct acpi_device_power_state *ps = &device->power.states[i];
+               char object_name[5] = { '_', 'P', 'R', '0' + i, '\0' };
 
+               /* Evaluate "_PRx" to se if power resources are referenced */
+               acpi_evaluate_reference(device->handle, object_name, NULL,
+                                       &ps->resources);
+               if (ps->resources.count) {
+                       device->power.flags.power_resources = 1;
+                       ps->flags.valid = 1;
+               }
 
-       spin_lock(&acpi_device_lock);
-       list_for_each_safe(node, next, &acpi_bus_drivers) {
-               struct acpi_driver *driver =
-                   container_of(node, struct acpi_driver, node);
-
-               atomic_inc(&driver->references);
-               spin_unlock(&acpi_device_lock);
-               if (!acpi_bus_match(device, driver)) {
-                       result = acpi_bus_driver_init(device, driver);
-                       if (!result)
-                               goto Done;
+               /* Evaluate "_PSx" to see if we can do explicit sets */
+               object_name[2] = 'S';
+               status = acpi_get_handle(device->handle, object_name, &handle);
+               if (ACPI_SUCCESS(status)) {
+                       ps->flags.explicit_set = 1;
+                       ps->flags.valid = 1;
                }
-               atomic_dec(&driver->references);
-               spin_lock(&acpi_device_lock);
-       }
-       spin_unlock(&acpi_device_lock);
 
-      Done:
-       return result;
-}
+               /* State is valid if we have some power control */
+               if (ps->resources.count || ps->flags.explicit_set)
+                       ps->flags.valid = 1;
 
-/* --------------------------------------------------------------------------
-                                 Device Enumeration
-   -------------------------------------------------------------------------- */
+               ps->power = -1; /* Unknown - driver assigned */
+               ps->latency = -1;       /* Unknown - driver assigned */
+       }
 
-acpi_status
-acpi_bus_get_ejd(acpi_handle handle, acpi_handle *ejd)
-{
-       acpi_status status;
-       acpi_handle tmp;
-       struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
-       union acpi_object *obj;
+       /* Set defaults for D0 and D3 states (always valid) */
+       device->power.states[ACPI_STATE_D0].flags.valid = 1;
+       device->power.states[ACPI_STATE_D0].power = 100;
+       device->power.states[ACPI_STATE_D3].flags.valid = 1;
+       device->power.states[ACPI_STATE_D3].power = 0;
 
-       status = acpi_get_handle(handle, "_EJD", &tmp);
-       if (ACPI_FAILURE(status))
-               return status;
+       /* TBD: System wake support and resource requirements. */
 
-       status = acpi_evaluate_object(handle, "_EJD", NULL, &buffer);
-       if (ACPI_SUCCESS(status)) {
-               obj = buffer.pointer;
-               status = acpi_get_handle(NULL, obj->string.pointer, ejd);
-               kfree(buffer.pointer);
-       }
-       return status;
-}
-EXPORT_SYMBOL_GPL(acpi_bus_get_ejd);
+       device->power.state = ACPI_STATE_UNKNOWN;
 
+       return 0;
+}
 
 static int acpi_bus_get_flags(struct acpi_device *device)
 {
@@ -782,6 +804,75 @@ static void acpi_device_get_busid(struct acpi_device *device,
        }
 }
 
+static int
+acpi_video_bus_match(struct acpi_device *device)
+{
+       acpi_handle h_dummy1;
+       acpi_handle h_dummy2;
+       acpi_handle h_dummy3;
+
+
+       if (!device)
+               return -EINVAL;
+
+       /* Since there is no HID, CID for ACPI Video drivers, we have
+        * to check well known required nodes for each feature we support.
+        */
+
+       /* Does this device able to support video switching ? */
+       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
+           ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
+               return 0;
+
+       /* Does this device able to retrieve a video ROM ? */
+       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
+               return 0;
+
+       /* Does this device able to configure which video head to be POSTed ? */
+       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
+           ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
+           ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
+               return 0;
+
+       return -ENODEV;
+}
+
+/*
+ * acpi_bay_match - see if a device is an ejectable driver bay
+ *
+ * If an acpi object is ejectable and has one of the ACPI ATA methods defined,
+ * then we can safely call it an ejectable drive bay
+ */
+static int acpi_bay_match(struct acpi_device *device){
+       acpi_status status;
+       acpi_handle handle;
+       acpi_handle tmp;
+       acpi_handle phandle;
+
+       handle = device->handle;
+
+       status = acpi_get_handle(handle, "_EJ0", &tmp);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       if ((ACPI_SUCCESS(acpi_get_handle(handle, "_GTF", &tmp))) ||
+               (ACPI_SUCCESS(acpi_get_handle(handle, "_GTM", &tmp))) ||
+               (ACPI_SUCCESS(acpi_get_handle(handle, "_STM", &tmp))) ||
+               (ACPI_SUCCESS(acpi_get_handle(handle, "_SDD", &tmp))))
+               return 0;
+
+       if (acpi_get_parent(handle, &phandle))
+               return -ENODEV;
+
+        if ((ACPI_SUCCESS(acpi_get_handle(phandle, "_GTF", &tmp))) ||
+                (ACPI_SUCCESS(acpi_get_handle(phandle, "_GTM", &tmp))) ||
+                (ACPI_SUCCESS(acpi_get_handle(phandle, "_STM", &tmp))) ||
+                (ACPI_SUCCESS(acpi_get_handle(phandle, "_SDD", &tmp))))
+                return 0;
+
+       return -ENODEV;
+}
+
 static void acpi_device_set_id(struct acpi_device *device,
                               struct acpi_device *parent, acpi_handle handle,
                               int type)
@@ -812,6 +903,16 @@ static void acpi_device_set_id(struct acpi_device *device,
                        device->pnp.bus_address = info->address;
                        device->flags.bus_address = 1;
                }
+
+               if(!(info->valid & (ACPI_VALID_HID | ACPI_VALID_CID))){
+                       status = acpi_video_bus_match(device);
+                       if(ACPI_SUCCESS(status))
+                               hid = ACPI_VIDEO_HID;
+
+                       status = acpi_bay_match(device);
+                       if (ACPI_SUCCESS(status))
+                               hid = ACPI_BAY_HID;
+               }
                break;
        case ACPI_BUS_TYPE_POWER:
                hid = ACPI_POWER_HID;
@@ -888,86 +989,24 @@ static int acpi_device_set_context(struct acpi_device *device, int type)
        return result;
 }
 
-static void acpi_device_get_debug_info(struct acpi_device *device,
-                                      acpi_handle handle, int type)
-{
-#ifdef CONFIG_ACPI_DEBUG_OUTPUT
-       char *type_string = NULL;
-       char name[80] = { '?', '\0' };
-       struct acpi_buffer buffer = { sizeof(name), name };
-
-       switch (type) {
-       case ACPI_BUS_TYPE_DEVICE:
-               type_string = "Device";
-               acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-               break;
-       case ACPI_BUS_TYPE_POWER:
-               type_string = "Power Resource";
-               acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-               break;
-       case ACPI_BUS_TYPE_PROCESSOR:
-               type_string = "Processor";
-               acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-               break;
-       case ACPI_BUS_TYPE_SYSTEM:
-               type_string = "System";
-               acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-               break;
-       case ACPI_BUS_TYPE_THERMAL:
-               type_string = "Thermal Zone";
-               acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
-               break;
-       case ACPI_BUS_TYPE_POWER_BUTTON:
-               type_string = "Power Button";
-               sprintf(name, "PWRB");
-               break;
-       case ACPI_BUS_TYPE_SLEEP_BUTTON:
-               type_string = "Sleep Button";
-               sprintf(name, "SLPB");
-               break;
-       }
-
-       printk(KERN_DEBUG "Found %s %s [%p]\n", type_string, name, handle);
-#endif                         /*CONFIG_ACPI_DEBUG_OUTPUT */
-}
-
 static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
 {
-       int result = 0;
-       struct acpi_driver *driver;
-
-
        if (!dev)
                return -EINVAL;
 
-       driver = dev->driver;
-
-       if ((driver) && (driver->ops.remove)) {
-
-               if (driver->ops.stop) {
-                       result = driver->ops.stop(dev, ACPI_BUS_REMOVAL_EJECT);
-                       if (result)
-                               return result;
-               }
-
-               result = dev->driver->ops.remove(dev, ACPI_BUS_REMOVAL_EJECT);
-               if (result) {
-                       return result;
-               }
-
-               atomic_dec(&dev->driver->references);
-               dev->driver = NULL;
-               acpi_driver_data(dev) = NULL;
-       }
+       dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
+       device_release_driver(&dev->dev);
 
        if (!rmdevice)
                return 0;
 
+       /*
+        * unbind _ADR-Based Devices when hot removal
+        */
        if (dev->flags.bus_address) {
                if ((dev->parent) && (dev->parent->ops.unbind))
                        dev->parent->ops.unbind(dev);
        }
-
        acpi_device_unregister(dev, ACPI_BUS_REMOVAL_EJECT);
 
        return 0;
@@ -975,7 +1014,8 @@ static int acpi_bus_remove(struct acpi_device *dev, int rmdevice)
 
 static int
 acpi_add_single_object(struct acpi_device **child,
-                      struct acpi_device *parent, acpi_handle handle, int type)
+                      struct acpi_device *parent, acpi_handle handle, int type,
+                       struct acpi_bus_ops *ops)
 {
        int result = 0;
        struct acpi_device *device = NULL;
@@ -992,6 +1032,8 @@ acpi_add_single_object(struct acpi_device **child,
 
        device->handle = handle;
        device->parent = parent;
+       device->bus_ops = *ops; /* workround for not call .start */
+
 
        acpi_device_get_busid(device, handle, type);
 
@@ -1076,33 +1118,16 @@ acpi_add_single_object(struct acpi_device **child,
        if ((result = acpi_device_set_context(device, type)))
                goto end;
 
-       acpi_device_get_debug_info(device, handle, type);
-
-       acpi_device_register(device, parent);
+       result = acpi_device_register(device, parent);
 
        /*
-        * Bind _ADR-Based Devices
-        * -----------------------
-        * If there's a a bus address (_ADR) then we utilize the parent's 
-        * 'bind' function (if exists) to bind the ACPI- and natively-
-        * enumerated device representations.
+        * Bind _ADR-Based Devices when hot add
         */
        if (device->flags.bus_address) {
                if (device->parent && device->parent->ops.bind)
                        device->parent->ops.bind(device);
        }
 
-       /*
-        * Locate & Attach Driver
-        * ----------------------
-        * If there's a hardware id (_HID) or compatible ids (_CID) we check
-        * to see if there's a driver installed for this kind of device.  Note
-        * that drivers can install before or after a device is enumerated.
-        *
-        * TBD: Assumes LDM provides driver hot-plug capability.
-        */
-       acpi_bus_find_driver(device);
-
       end:
        if (!result)
                *child = device;
@@ -1188,14 +1213,14 @@ static int acpi_bus_scan(struct acpi_device *start, struct acpi_bus_ops *ops)
 
                if (ops->acpi_op_add)
                        status = acpi_add_single_object(&child, parent,
-                                                       chandle, type);
+                               chandle, type, ops);
                else
                        status = acpi_bus_get_device(chandle, &child);
 
                if (ACPI_FAILURE(status))
                        continue;
 
-               if (ops->acpi_op_start) {
+               if (ops->acpi_op_start && !(ops->acpi_op_add)) {
                        status = acpi_start_single_object(child);
                        if (ACPI_FAILURE(status))
                                continue;
@@ -1233,13 +1258,13 @@ acpi_bus_add(struct acpi_device **child,
        int result;
        struct acpi_bus_ops ops;
 
+       memset(&ops, 0, sizeof(ops));
+       ops.acpi_op_add = 1;
 
-       result = acpi_add_single_object(child, parent, handle, type);
-       if (!result) {
-               memset(&ops, 0, sizeof(ops));
-               ops.acpi_op_add = 1;
+       result = acpi_add_single_object(child, parent, handle, type, &ops);
+       if (!result)
                result = acpi_bus_scan(*child, &ops);
-       }
+
        return result;
 }
 
@@ -1325,127 +1350,35 @@ static int acpi_bus_scan_fixed(struct acpi_device *root)
 {
        int result = 0;
        struct acpi_device *device = NULL;
-
+       struct acpi_bus_ops ops;
 
        if (!root)
                return -ENODEV;
 
+       memset(&ops, 0, sizeof(ops));
+       ops.acpi_op_add = 1;
+       ops.acpi_op_start = 1;
+
        /*
         * Enumerate all fixed-feature devices.
         */
-       if (acpi_fadt.pwr_button == 0) {
+       if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) {
                result = acpi_add_single_object(&device, acpi_root,
                                                NULL,
-                                               ACPI_BUS_TYPE_POWER_BUTTON);
-               if (!result)
-                       result = acpi_start_single_object(device);
+                                               ACPI_BUS_TYPE_POWER_BUTTON,
+                                               &ops);
        }
 
-       if (acpi_fadt.sleep_button == 0) {
+       if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
                result = acpi_add_single_object(&device, acpi_root,
                                                NULL,
-                                               ACPI_BUS_TYPE_SLEEP_BUTTON);
-               if (!result)
-                       result = acpi_start_single_object(device);
+                                               ACPI_BUS_TYPE_SLEEP_BUTTON,
+                                               &ops);
        }
 
        return result;
 }
 
-
-static inline struct acpi_device * to_acpi_dev(struct device * dev)
-{
-       return container_of(dev, struct acpi_device, dev);
-}
-
-
-static int root_suspend(struct acpi_device * acpi_dev, pm_message_t state)
-{
-       struct acpi_device * dev, * next;
-       int result;
-
-       spin_lock(&acpi_device_lock);
-       list_for_each_entry_safe_reverse(dev, next, &acpi_device_list, g_list) {
-               if (dev->driver && dev->driver->ops.suspend) {
-                       spin_unlock(&acpi_device_lock);
-                       result = dev->driver->ops.suspend(dev, 0);
-                       if (result) {
-                               printk(KERN_ERR PREFIX "[%s - %s] Suspend failed: %d\n",
-                                      acpi_device_name(dev),
-                                      acpi_device_bid(dev), result);
-                       }
-                       spin_lock(&acpi_device_lock);
-               }
-       }
-       spin_unlock(&acpi_device_lock);
-       return 0;
-}
-
-
-static int acpi_device_suspend(struct device * dev, pm_message_t state)
-{
-       struct acpi_device * acpi_dev = to_acpi_dev(dev);
-
-       /*
-        * For now, we should only register 1 generic device -
-        * the ACPI root device - and from there, we walk the
-        * tree of ACPI devices to suspend each one using the
-        * ACPI driver methods.
-        */
-       if (acpi_dev->handle == ACPI_ROOT_OBJECT)
-               root_suspend(acpi_dev, state);
-       return 0;
-}
-
-
-
-static int root_resume(struct acpi_device * acpi_dev)
-{
-       struct acpi_device * dev, * next;
-       int result;
-
-       spin_lock(&acpi_device_lock);
-       list_for_each_entry_safe(dev, next, &acpi_device_list, g_list) {
-               if (dev->driver && dev->driver->ops.resume) {
-                       spin_unlock(&acpi_device_lock);
-                       result = dev->driver->ops.resume(dev, 0);
-                       if (result) {
-                               printk(KERN_ERR PREFIX "[%s - %s] resume failed: %d\n",
-                                      acpi_device_name(dev),
-                                      acpi_device_bid(dev), result);
-                       }
-                       spin_lock(&acpi_device_lock);
-               }
-       }
-       spin_unlock(&acpi_device_lock);
-       return 0;
-}
-
-
-static int acpi_device_resume(struct device * dev)
-{
-       struct acpi_device * acpi_dev = to_acpi_dev(dev);
-
-       /*
-        * For now, we should only register 1 generic device -
-        * the ACPI root device - and from there, we walk the
-        * tree of ACPI devices to resume each one using the
-        * ACPI driver methods.
-        */
-       if (acpi_dev->handle == ACPI_ROOT_OBJECT)
-               root_resume(acpi_dev);
-       return 0;
-}
-
-
-static struct bus_type acpi_bus_type = {
-       .name           = "acpi",
-       .suspend        = acpi_device_suspend,
-       .resume         = acpi_device_resume,
-};
-
-
-
 static int __init acpi_scan_init(void)
 {
        int result;
@@ -1455,9 +1388,9 @@ static int __init acpi_scan_init(void)
        if (acpi_disabled)
                return 0;
 
-       result = kset_register(&acpi_namespace_kset);
-       if (result < 0)
-               printk(KERN_ERR PREFIX "kset_register error: %d\n", result);
+       memset(&ops, 0, sizeof(ops));
+       ops.acpi_op_add = 1;
+       ops.acpi_op_start = 1;
 
        result = bus_register(&acpi_bus_type);
        if (result) {
@@ -1469,32 +1402,16 @@ static int __init acpi_scan_init(void)
         * Create the root device in the bus's device tree
         */
        result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT,
-                                       ACPI_BUS_TYPE_SYSTEM);
+                                       ACPI_BUS_TYPE_SYSTEM, &ops);
        if (result)
                goto Done;
 
-       result = acpi_start_single_object(acpi_root);
-       if (result)
-               goto Done;
-
-       acpi_root->dev.bus = &acpi_bus_type;
-       snprintf(acpi_root->dev.bus_id, BUS_ID_SIZE, "%s", acpi_bus_type.name);
-       result = device_register(&acpi_root->dev);
-       if (result) {
-               /* We don't want to quit even if we failed to add suspend/resume */
-               printk(KERN_ERR PREFIX "Could not register device\n");
-       }
-
        /*
         * Enumerate devices in the ACPI namespace.
         */
        result = acpi_bus_scan_fixed(acpi_root);
-       if (!result) {
-               memset(&ops, 0, sizeof(ops));
-               ops.acpi_op_add = 1;
-               ops.acpi_op_start = 1;
+       if (!result)
                result = acpi_bus_scan(acpi_root, &ops);
-       }
 
        if (result)
                acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
index 3496257..ccc11b3 100644 (file)
@@ -73,7 +73,7 @@ acpi_system_write_sleep(struct file *file,
 static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
 {
        u32 sec, min, hr;
-       u32 day, mo, yr;
+       u32 day, mo, yr, cent = 0;
        unsigned char rtc_control = 0;
        unsigned long flags;
 
@@ -87,20 +87,19 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
        rtc_control = CMOS_READ(RTC_CONTROL);
 
        /* If we ever get an FACP with proper values... */
-       if (acpi_gbl_FADT->day_alrm)
+       if (acpi_gbl_FADT.day_alarm)
                /* ACPI spec: only low 6 its should be cared */
-               day = CMOS_READ(acpi_gbl_FADT->day_alrm) & 0x3F;
+               day = CMOS_READ(acpi_gbl_FADT.day_alarm) & 0x3F;
        else
                day = CMOS_READ(RTC_DAY_OF_MONTH);
-       if (acpi_gbl_FADT->mon_alrm)
-               mo = CMOS_READ(acpi_gbl_FADT->mon_alrm);
+       if (acpi_gbl_FADT.month_alarm)
+               mo = CMOS_READ(acpi_gbl_FADT.month_alarm);
        else
                mo = CMOS_READ(RTC_MONTH);
-       if (acpi_gbl_FADT->century)
-               yr = CMOS_READ(acpi_gbl_FADT->century) * 100 +
-                   CMOS_READ(RTC_YEAR);
-       else
-               yr = CMOS_READ(RTC_YEAR);
+       if (acpi_gbl_FADT.century)
+               cent = CMOS_READ(acpi_gbl_FADT.century);
+
+       yr = CMOS_READ(RTC_YEAR);
 
        spin_unlock_irqrestore(&rtc_lock, flags);
 
@@ -111,10 +110,11 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
                BCD_TO_BIN(day);
                BCD_TO_BIN(mo);
                BCD_TO_BIN(yr);
+               BCD_TO_BIN(cent);
        }
 
        /* we're trusting the FADT (see above) */
-       if (!acpi_gbl_FADT->century)
+       if (!acpi_gbl_FADT.century)
                /* If we're not trusting the FADT, we should at least make it
                 * right for _this_ century... ehm, what is _this_ century?
                 *
@@ -134,6 +134,8 @@ static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
                 *
                 */
                yr += 2000;
+       else
+               yr += cent * 100;
 
        seq_printf(seq, "%4.4u-", yr);
        (mo > 12) ? seq_puts(seq, "**-") : seq_printf(seq, "%2.2u-", mo);
@@ -317,12 +319,12 @@ acpi_system_write_alarm(struct file *file,
         * offsets into the CMOS RAM here -- which for some reason are pointing
         * to the RTC area of memory.
         */
-       if (acpi_gbl_FADT->day_alrm)
-               CMOS_WRITE(day, acpi_gbl_FADT->day_alrm);
-       if (acpi_gbl_FADT->mon_alrm)
-               CMOS_WRITE(mo, acpi_gbl_FADT->mon_alrm);
-       if (acpi_gbl_FADT->century)
-               CMOS_WRITE(yr / 100, acpi_gbl_FADT->century);
+       if (acpi_gbl_FADT.day_alarm)
+               CMOS_WRITE(day, acpi_gbl_FADT.day_alarm);
+       if (acpi_gbl_FADT.month_alarm)
+               CMOS_WRITE(mo, acpi_gbl_FADT.month_alarm);
+       if (acpi_gbl_FADT.century)
+               CMOS_WRITE(yr / 100, acpi_gbl_FADT.century);
        /* enable the rtc alarm interrupt */
        rtc_control |= RTC_AIE;
        CMOS_WRITE(rtc_control, RTC_CONTROL);
index d86dcb3..7147b0b 100644 (file)
 
 #define _COMPONENT             ACPI_SYSTEM_COMPONENT
 ACPI_MODULE_NAME("acpi_system")
+#ifdef MODULE_PARAM_PREFIX
+#undef MODULE_PARAM_PREFIX
+#endif
+#define MODULE_PARAM_PREFIX "acpi."
+
 #define ACPI_SYSTEM_CLASS              "system"
 #define ACPI_SYSTEM_DRIVER_NAME                "ACPI System Driver"
 #define ACPI_SYSTEM_DEVICE_NAME                "System"
@@ -39,11 +44,24 @@ ACPI_MODULE_NAME("acpi_system")
 #define ACPI_SYSTEM_FILE_EVENT         "event"
 #define ACPI_SYSTEM_FILE_DSDT          "dsdt"
 #define ACPI_SYSTEM_FILE_FADT          "fadt"
-extern struct fadt_descriptor acpi_fadt;
+
+/*
+ * Make ACPICA version work as module param
+ */
+static int param_get_acpica_version(char *buffer, struct kernel_param *kp) {
+       int result;
+
+       result = sprintf(buffer, "%x", ACPI_CA_VERSION);
+
+       return result;
+}
+
+module_param_call(acpica_version, NULL, param_get_acpica_version, NULL, 0444);
 
 /* --------------------------------------------------------------------------
                               FS Interface (/proc)
    -------------------------------------------------------------------------- */
+#ifdef CONFIG_ACPI_PROCFS
 
 static int acpi_system_read_info(struct seq_file *seq, void *offset)
 {
@@ -63,6 +81,7 @@ static const struct file_operations acpi_system_info_ops = {
        .llseek = seq_lseek,
        .release = single_release,
 };
+#endif
 
 static ssize_t acpi_system_read_dsdt(struct file *, char __user *, size_t,
                                     loff_t *);
@@ -76,17 +95,16 @@ acpi_system_read_dsdt(struct file *file,
                      char __user * buffer, size_t count, loff_t * ppos)
 {
        acpi_status status = AE_OK;
-       struct acpi_buffer dsdt = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_table_header *dsdt = NULL;
        ssize_t res;
 
 
-       status = acpi_get_table(ACPI_TABLE_ID_DSDT, 1, &dsdt);
+       status = acpi_get_table(ACPI_SIG_DSDT, 1, &dsdt);
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
        res = simple_read_from_buffer(buffer, count, ppos,
-                                     dsdt.pointer, dsdt.length);
-       kfree(dsdt.pointer);
+                                     dsdt, dsdt->length);
 
        return res;
 }
@@ -103,17 +121,16 @@ acpi_system_read_fadt(struct file *file,
                      char __user * buffer, size_t count, loff_t * ppos)
 {
        acpi_status status = AE_OK;
-       struct acpi_buffer fadt = { ACPI_ALLOCATE_BUFFER, NULL };
+       struct acpi_table_header *fadt = NULL;
        ssize_t res;
 
 
-       status = acpi_get_table(ACPI_TABLE_ID_FADT, 1, &fadt);
+       status = acpi_get_table(ACPI_SIG_FADT, 1, &fadt);
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
        res = simple_read_from_buffer(buffer, count, ppos,
-                                     fadt.pointer, fadt.length);
-       kfree(fadt.pointer);
+                                     fadt, fadt->length);
 
        return res;
 }
@@ -128,6 +145,7 @@ static int __init acpi_system_init(void)
        if (acpi_disabled)
                return 0;
 
+#ifdef CONFIG_ACPI_PROCFS
        /* 'info' [R] */
        name = ACPI_SYSTEM_FILE_INFO;
        entry = create_proc_entry(name, S_IRUGO, acpi_root_dir);
@@ -136,6 +154,7 @@ static int __init acpi_system_init(void)
        else {
                entry->proc_fops = &acpi_system_info_ops;
        }
+#endif
 
        /* 'dsdt' [R] */
        name = ACPI_SYSTEM_FILE_DSDT;
@@ -159,7 +178,9 @@ static int __init acpi_system_init(void)
       Error:
        remove_proc_entry(ACPI_SYSTEM_FILE_FADT, acpi_root_dir);
        remove_proc_entry(ACPI_SYSTEM_FILE_DSDT, acpi_root_dir);
+#ifdef CONFIG_ACPI_PROCFS
        remove_proc_entry(ACPI_SYSTEM_FILE_INFO, acpi_root_dir);
+#endif
 
        error = -EFAULT;
        goto Done;
index ffa30c9..ba4cb20 100644 (file)
 
 #define ACPI_MAX_TABLES                128
 
-static char *acpi_table_signatures[ACPI_TABLE_COUNT] = {
-       [ACPI_TABLE_UNKNOWN] = "????",
-       [ACPI_APIC] = "APIC",
-       [ACPI_BOOT] = "BOOT",
-       [ACPI_DBGP] = "DBGP",
-       [ACPI_DSDT] = "DSDT",
-       [ACPI_ECDT] = "ECDT",
-       [ACPI_ETDT] = "ETDT",
-       [ACPI_FADT] = "FACP",
-       [ACPI_FACS] = "FACS",
-       [ACPI_OEMX] = "OEM",
-       [ACPI_PSDT] = "PSDT",
-       [ACPI_SBST] = "SBST",
-       [ACPI_SLIT] = "SLIT",
-       [ACPI_SPCR] = "SPCR",
-       [ACPI_SRAT] = "SRAT",
-       [ACPI_SSDT] = "SSDT",
-       [ACPI_SPMI] = "SPMI",
-       [ACPI_HPET] = "HPET",
-       [ACPI_MCFG] = "MCFG",
-};
-
 static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low" };
 static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level" };
 
-/* System Description Table (RSDT/XSDT) */
-struct acpi_table_sdt {
-       unsigned long pa;
-       enum acpi_table_id id;
-       unsigned long size;
-} __attribute__ ((packed));
-
-static unsigned long sdt_pa;   /* Physical Address */
-static unsigned long sdt_count;        /* Table count */
+static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
 
-static struct acpi_table_sdt sdt_entry[ACPI_MAX_TABLES] __initdata;
-
-void acpi_table_print(struct acpi_table_header *header, unsigned long phys_addr)
-{
-       char *name = NULL;
-
-       if (!header)
-               return;
-
-       /* Some table signatures aren't good table names */
-
-       if (!strncmp((char *)&header->signature,
-                    acpi_table_signatures[ACPI_APIC],
-                    sizeof(header->signature))) {
-               name = "MADT";
-       } else if (!strncmp((char *)&header->signature,
-                           acpi_table_signatures[ACPI_FADT],
-                           sizeof(header->signature))) {
-               name = "FADT";
-       } else
-               name = header->signature;
-
-       printk(KERN_DEBUG PREFIX
-              "%.4s (v%3.3d %6.6s %8.8s 0x%08x %.4s 0x%08x) @ 0x%p\n", name,
-              header->revision, header->oem_id, header->oem_table_id,
-              header->oem_revision, header->asl_compiler_id,
-              header->asl_compiler_revision, (void *)phys_addr);
-}
-
-void acpi_table_print_madt_entry(acpi_table_entry_header * header)
+void acpi_table_print_madt_entry(struct acpi_subtable_header * header)
 {
        if (!header)
                return;
 
        switch (header->type) {
 
-       case ACPI_MADT_LAPIC:
+       case ACPI_MADT_TYPE_LOCAL_APIC:
                {
-                       struct acpi_table_lapic *p =
-                           (struct acpi_table_lapic *)header;
+                       struct acpi_madt_local_apic *p =
+                           (struct acpi_madt_local_apic *)header;
                        printk(KERN_INFO PREFIX
                               "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n",
-                              p->acpi_id, p->id,
-                              p->flags.enabled ? "enabled" : "disabled");
+                              p->processor_id, p->id,
+                              (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
                }
                break;
 
-       case ACPI_MADT_IOAPIC:
+       case ACPI_MADT_TYPE_IO_APIC:
                {
-                       struct acpi_table_ioapic *p =
-                           (struct acpi_table_ioapic *)header;
+                       struct acpi_madt_io_apic *p =
+                           (struct acpi_madt_io_apic *)header;
                        printk(KERN_INFO PREFIX
                               "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n",
                               p->id, p->address, p->global_irq_base);
                }
                break;
 
-       case ACPI_MADT_INT_SRC_OVR:
+       case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
                {
-                       struct acpi_table_int_src_ovr *p =
-                           (struct acpi_table_int_src_ovr *)header;
+                       struct acpi_madt_interrupt_override *p =
+                           (struct acpi_madt_interrupt_override *)header;
                        printk(KERN_INFO PREFIX
                               "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n",
-                              p->bus, p->bus_irq, p->global_irq,
-                              mps_inti_flags_polarity[p->flags.polarity],
-                              mps_inti_flags_trigger[p->flags.trigger]);
-                       if (p->flags.reserved)
+                              p->bus, p->source_irq, p->global_irq,
+                              mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+                              mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]);
+                       if (p->inti_flags  &
+                           ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK))
                                printk(KERN_INFO PREFIX
                                       "INT_SRC_OVR unexpected reserved flags: 0x%x\n",
-                                      p->flags.reserved);
+                                      p->inti_flags  &
+                                       ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK));
 
                }
                break;
 
-       case ACPI_MADT_NMI_SRC:
+       case ACPI_MADT_TYPE_NMI_SOURCE:
                {
-                       struct acpi_table_nmi_src *p =
-                           (struct acpi_table_nmi_src *)header;
+                       struct acpi_madt_nmi_source *p =
+                           (struct acpi_madt_nmi_source *)header;
                        printk(KERN_INFO PREFIX
                               "NMI_SRC (%s %s global_irq %d)\n",
-                              mps_inti_flags_polarity[p->flags.polarity],
-                              mps_inti_flags_trigger[p->flags.trigger],
+                              mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+                              mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
                               p->global_irq);
                }
                break;
 
-       case ACPI_MADT_LAPIC_NMI:
+       case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
                {
-                       struct acpi_table_lapic_nmi *p =
-                           (struct acpi_table_lapic_nmi *)header;
+                       struct acpi_madt_local_apic_nmi *p =
+                           (struct acpi_madt_local_apic_nmi *)header;
                        printk(KERN_INFO PREFIX
                               "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n",
-                              p->acpi_id,
-                              mps_inti_flags_polarity[p->flags.polarity],
-                              mps_inti_flags_trigger[p->flags.trigger],
+                              p->processor_id,
+                              mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK  ],
+                              mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
                               p->lint);
                }
                break;
 
-       case ACPI_MADT_LAPIC_ADDR_OVR:
+       case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE:
                {
-                       struct acpi_table_lapic_addr_ovr *p =
-                           (struct acpi_table_lapic_addr_ovr *)header;
+                       struct acpi_madt_local_apic_override *p =
+                           (struct acpi_madt_local_apic_override *)header;
                        printk(KERN_INFO PREFIX
                               "LAPIC_ADDR_OVR (address[%p])\n",
                               (void *)(unsigned long)p->address);
                }
                break;
 
-       case ACPI_MADT_IOSAPIC:
+       case ACPI_MADT_TYPE_IO_SAPIC:
                {
-                       struct acpi_table_iosapic *p =
-                           (struct acpi_table_iosapic *)header;
+                       struct acpi_madt_io_sapic *p =
+                           (struct acpi_madt_io_sapic *)header;
                        printk(KERN_INFO PREFIX
                               "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n",
                               p->id, (void *)(unsigned long)p->address,
@@ -193,26 +136,26 @@ void acpi_table_print_madt_entry(acpi_table_entry_header * header)
                }
                break;
 
-       case ACPI_MADT_LSAPIC:
+       case ACPI_MADT_TYPE_LOCAL_SAPIC:
                {
-                       struct acpi_table_lsapic *p =
-                           (struct acpi_table_lsapic *)header;
+                       struct acpi_madt_local_sapic *p =
+                           (struct acpi_madt_local_sapic *)header;
                        printk(KERN_INFO PREFIX
                               "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n",
-                              p->acpi_id, p->id, p->eid,
-                              p->flags.enabled ? "enabled" : "disabled");
+                              p->processor_id, p->id, p->eid,
+                              (p->lapic_flags & ACPI_MADT_ENABLED) ? "enabled" : "disabled");
                }
                break;
 
-       case ACPI_MADT_PLAT_INT_SRC:
+       case ACPI_MADT_TYPE_INTERRUPT_SOURCE:
                {
-                       struct acpi_table_plat_int_src *p =
-                           (struct acpi_table_plat_int_src *)header;
+                       struct acpi_madt_interrupt_source *p =
+                           (struct acpi_madt_interrupt_source *)header;
                        printk(KERN_INFO PREFIX
                               "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n",
-                              mps_inti_flags_polarity[p->flags.polarity],
-                              mps_inti_flags_trigger[p->flags.trigger],
-                              p->type, p->id, p->eid, p->iosapic_vector,
+                              mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK],
+                              mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2],
+                              p->type, p->id, p->eid, p->io_sapic_vector,
                               p->global_irq);
                }
                break;
@@ -225,342 +168,76 @@ void acpi_table_print_madt_entry(acpi_table_entry_header * header)
        }
 }
 
-static int
-acpi_table_compute_checksum(void *table_pointer, unsigned long length)
-{
-       u8 *p = table_pointer;
-       unsigned long remains = length;
-       unsigned long sum = 0;
-
-       if (!p || !length)
-               return -EINVAL;
-
-       while (remains--)
-               sum += *p++;
-
-       return (sum & 0xFF);
-}
 
-/*
- * acpi_get_table_header_early()
- * for acpi_blacklisted(), acpi_table_get_sdt()
- */
 int __init
-acpi_get_table_header_early(enum acpi_table_id id,
-                           struct acpi_table_header **header)
-{
-       unsigned int i;
-       enum acpi_table_id temp_id;
-
-       /* DSDT is different from the rest */
-       if (id == ACPI_DSDT)
-               temp_id = ACPI_FADT;
-       else
-               temp_id = id;
-
-       /* Locate the table. */
-
-       for (i = 0; i < sdt_count; i++) {
-               if (sdt_entry[i].id != temp_id)
-                       continue;
-               *header = (void *)
-                   __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
-               if (!*header) {
-                       printk(KERN_WARNING PREFIX "Unable to map %s\n",
-                              acpi_table_signatures[temp_id]);
-                       return -ENODEV;
-               }
-               break;
-       }
-
-       if (!*header) {
-               printk(KERN_WARNING PREFIX "%s not present\n",
-                      acpi_table_signatures[id]);
-               return -ENODEV;
-       }
-
-       /* Map the DSDT header via the pointer in the FADT */
-       if (id == ACPI_DSDT) {
-               struct fadt_descriptor *fadt =
-                   (struct fadt_descriptor *)*header;
-
-               if (fadt->revision == 3 && fadt->Xdsdt) {
-                       *header = (void *)__acpi_map_table(fadt->Xdsdt,
-                                                          sizeof(struct
-                                                                 acpi_table_header));
-               } else if (fadt->V1_dsdt) {
-                       *header = (void *)__acpi_map_table(fadt->V1_dsdt,
-                                                          sizeof(struct
-                                                                 acpi_table_header));
-               } else
-                       *header = NULL;
-
-               if (!*header) {
-                       printk(KERN_WARNING PREFIX "Unable to map DSDT\n");
-                       return -ENODEV;
-               }
-       }
-
-       return 0;
-}
-
-int __init
-acpi_table_parse_madt_family(enum acpi_table_id id,
+acpi_table_parse_madt_family(char *id,
                             unsigned long madt_size,
                             int entry_id,
                             acpi_madt_entry_handler handler,
                             unsigned int max_entries)
 {
-       void *madt = NULL;
-       acpi_table_entry_header *entry;
+       struct acpi_table_header *madt = NULL;
+       struct acpi_subtable_header *entry;
        unsigned int count = 0;
        unsigned long madt_end;
-       unsigned int i;
 
        if (!handler)
                return -EINVAL;
 
        /* Locate the MADT (if exists). There should only be one. */
-
-       for (i = 0; i < sdt_count; i++) {
-               if (sdt_entry[i].id != id)
-                       continue;
-               madt = (void *)
-                   __acpi_map_table(sdt_entry[i].pa, sdt_entry[i].size);
-               if (!madt) {
-                       printk(KERN_WARNING PREFIX "Unable to map %s\n",
-                              acpi_table_signatures[id]);
-                       return -ENODEV;
-               }
-               break;
-       }
+       acpi_get_table(id, 0, &madt);
 
        if (!madt) {
-               printk(KERN_WARNING PREFIX "%s not present\n",
-                      acpi_table_signatures[id]);
+               printk(KERN_WARNING PREFIX "%4.4s not present\n", id);
                return -ENODEV;
        }
 
-       madt_end = (unsigned long)madt + sdt_entry[i].size;
+       madt_end = (unsigned long)madt + madt->length;
 
        /* Parse all entries looking for a match. */
 
-       entry = (acpi_table_entry_header *)
+       entry = (struct acpi_subtable_header *)
            ((unsigned long)madt + madt_size);
 
-       while (((unsigned long)entry) + sizeof(acpi_table_entry_header) <
+       while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
               madt_end) {
                if (entry->type == entry_id
                    && (!max_entries || count++ < max_entries))
                        if (handler(entry, madt_end))
                                return -EINVAL;
 
-               entry = (acpi_table_entry_header *)
+               entry = (struct acpi_subtable_header *)
                    ((unsigned long)entry + entry->length);
        }
        if (max_entries && count > max_entries) {
-               printk(KERN_WARNING PREFIX "[%s:0x%02x] ignored %i entries of "
-                      "%i found\n", acpi_table_signatures[id], entry_id,
-                      count - max_entries, count);
+               printk(KERN_WARNING PREFIX "[%4.4s:0x%02x] ignored %i entries of "
+                      "%i found\n", id, entry_id, count - max_entries, count);
        }
 
        return count;
 }
 
 int __init
-acpi_table_parse_madt(enum acpi_madt_entry_id id,
+acpi_table_parse_madt(enum acpi_madt_type id,
                      acpi_madt_entry_handler handler, unsigned int max_entries)
 {
-       return acpi_table_parse_madt_family(ACPI_APIC,
+       return acpi_table_parse_madt_family(ACPI_SIG_MADT,
                                            sizeof(struct acpi_table_madt), id,
                                            handler, max_entries);
 }
 
-int __init acpi_table_parse(enum acpi_table_id id, acpi_table_handler handler)
+int __init acpi_table_parse(char *id, acpi_table_handler handler)
 {
-       int count = 0;
-       unsigned int i = 0;
-
+       struct acpi_table_header *table = NULL;
        if (!handler)
                return -EINVAL;
 
-       for (i = 0; i < sdt_count; i++) {
-               if (sdt_entry[i].id != id)
-                       continue;
-               count++;
-               if (count == 1)
-                       handler(sdt_entry[i].pa, sdt_entry[i].size);
-
-               else
-                       printk(KERN_WARNING PREFIX
-                              "%d duplicate %s table ignored.\n", count,
-                              acpi_table_signatures[id]);
-       }
-
-       return count;
-}
-
-static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp)
-{
-       struct acpi_table_header *header = NULL;
-       unsigned int i, id = 0;
-
-       if (!rsdp)
-               return -EINVAL;
-
-       /* First check XSDT (but only on ACPI 2.0-compatible systems) */
-
-       if ((rsdp->revision >= 2) &&
-           (((struct acpi20_table_rsdp *)rsdp)->xsdt_address)) {
-
-               struct acpi_table_xsdt *mapped_xsdt = NULL;
-
-               sdt_pa = ((struct acpi20_table_rsdp *)rsdp)->xsdt_address;
-
-               /* map in just the header */
-               header = (struct acpi_table_header *)
-                   __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
-
-               if (!header) {
-                       printk(KERN_WARNING PREFIX
-                              "Unable to map XSDT header\n");
-                       return -ENODEV;
-               }
-
-               /* remap in the entire table before processing */
-               mapped_xsdt = (struct acpi_table_xsdt *)
-                   __acpi_map_table(sdt_pa, header->length);
-               if (!mapped_xsdt) {
-                       printk(KERN_WARNING PREFIX "Unable to map XSDT\n");
-                       return -ENODEV;
-               }
-               header = &mapped_xsdt->header;
-
-               if (strncmp(header->signature, "XSDT", 4)) {
-                       printk(KERN_WARNING PREFIX
-                              "XSDT signature incorrect\n");
-                       return -ENODEV;
-               }
-
-               if (acpi_table_compute_checksum(header, header->length)) {
-                       printk(KERN_WARNING PREFIX "Invalid XSDT checksum\n");
-                       return -ENODEV;
-               }
-
-               sdt_count =
-                   (header->length - sizeof(struct acpi_table_header)) >> 3;
-               if (sdt_count > ACPI_MAX_TABLES) {
-                       printk(KERN_WARNING PREFIX
-                              "Truncated %lu XSDT entries\n",
-                              (sdt_count - ACPI_MAX_TABLES));
-                       sdt_count = ACPI_MAX_TABLES;
-               }
-
-               for (i = 0; i < sdt_count; i++)
-                       sdt_entry[i].pa = (unsigned long)mapped_xsdt->entry[i];
-       }
-
-       /* Then check RSDT */
-
-       else if (rsdp->rsdt_address) {
-
-               struct acpi_table_rsdt *mapped_rsdt = NULL;
-
-               sdt_pa = rsdp->rsdt_address;
-
-               /* map in just the header */
-               header = (struct acpi_table_header *)
-                   __acpi_map_table(sdt_pa, sizeof(struct acpi_table_header));
-               if (!header) {
-                       printk(KERN_WARNING PREFIX
-                              "Unable to map RSDT header\n");
-                       return -ENODEV;
-               }
-
-               /* remap in the entire table before processing */
-               mapped_rsdt = (struct acpi_table_rsdt *)
-                   __acpi_map_table(sdt_pa, header->length);
-               if (!mapped_rsdt) {
-                       printk(KERN_WARNING PREFIX "Unable to map RSDT\n");
-                       return -ENODEV;
-               }
-               header = &mapped_rsdt->header;
-
-               if (strncmp(header->signature, "RSDT", 4)) {
-                       printk(KERN_WARNING PREFIX
-                              "RSDT signature incorrect\n");
-                       return -ENODEV;
-               }
-
-               if (acpi_table_compute_checksum(header, header->length)) {
-                       printk(KERN_WARNING PREFIX "Invalid RSDT checksum\n");
-                       return -ENODEV;
-               }
-
-               sdt_count =
-                   (header->length - sizeof(struct acpi_table_header)) >> 2;
-               if (sdt_count > ACPI_MAX_TABLES) {
-                       printk(KERN_WARNING PREFIX
-                              "Truncated %lu RSDT entries\n",
-                              (sdt_count - ACPI_MAX_TABLES));
-                       sdt_count = ACPI_MAX_TABLES;
-               }
-
-               for (i = 0; i < sdt_count; i++)
-                       sdt_entry[i].pa = (unsigned long)mapped_rsdt->entry[i];
-       }
-
-       else {
-               printk(KERN_WARNING PREFIX
-                      "No System Description Table (RSDT/XSDT) specified in RSDP\n");
-               return -ENODEV;
-       }
-
-       acpi_table_print(header, sdt_pa);
-
-       for (i = 0; i < sdt_count; i++) {
-
-               /* map in just the header */
-               header = (struct acpi_table_header *)
-                   __acpi_map_table(sdt_entry[i].pa,
-                                    sizeof(struct acpi_table_header));
-               if (!header)
-                       continue;
-
-               /* remap in the entire table before processing */
-               header = (struct acpi_table_header *)
-                   __acpi_map_table(sdt_entry[i].pa, header->length);
-               if (!header)
-                       continue;
-
-               acpi_table_print(header, sdt_entry[i].pa);
-
-               if (acpi_table_compute_checksum(header, header->length)) {
-                       printk(KERN_WARNING "  >>> ERROR: Invalid checksum\n");
-                       continue;
-               }
-
-               sdt_entry[i].size = header->length;
-
-               for (id = 0; id < ACPI_TABLE_COUNT; id++) {
-                       if (!strncmp((char *)&header->signature,
-                                    acpi_table_signatures[id],
-                                    sizeof(header->signature))) {
-                               sdt_entry[i].id = id;
-                       }
-               }
-       }
-
-       /* 
-        * The DSDT is *not* in the RSDT (why not? no idea.) but we want
-        * to print its info, because this is what people usually blacklist
-        * against. Unfortunately, we don't know the phys_addr, so just
-        * print 0. Maybe no one will notice.
-        */
-       if (!acpi_get_table_header_early(ACPI_DSDT, &header))
-               acpi_table_print(header, 0);
-
-       return 0;
+       acpi_get_table(id, 0, &table);
+       if (table) {
+               handler(table);
+               return 1;
+       } else
+               return 0;
 }
 
 /*
@@ -568,54 +245,13 @@ static int __init acpi_table_get_sdt(struct acpi_table_rsdp *rsdp)
  *
  * find RSDP, find and checksum SDT/XSDT.
  * checksum all tables, print SDT/XSDT
- * 
+ *
  * result: sdt_entry[] is initialized
  */
 
+
 int __init acpi_table_init(void)
 {
-       struct acpi_table_rsdp *rsdp = NULL;
-       unsigned long rsdp_phys = 0;
-       int result = 0;
-
-       /* Locate and map the Root System Description Table (RSDP) */
-
-       rsdp_phys = acpi_find_rsdp();
-       if (!rsdp_phys) {
-               printk(KERN_ERR PREFIX "Unable to locate RSDP\n");
-               return -ENODEV;
-       }
-
-       rsdp = (struct acpi_table_rsdp *)__acpi_map_table(rsdp_phys,
-               sizeof(struct acpi_table_rsdp));
-       if (!rsdp) {
-               printk(KERN_WARNING PREFIX "Unable to map RSDP\n");
-               return -ENODEV;
-       }
-
-       printk(KERN_DEBUG PREFIX
-              "RSDP (v%3.3d %6.6s                                ) @ 0x%p\n",
-              rsdp->revision, rsdp->oem_id, (void *)rsdp_phys);
-
-       if (rsdp->revision < 2)
-               result =
-                   acpi_table_compute_checksum(rsdp,
-                                               sizeof(struct acpi_table_rsdp));
-       else
-               result =
-                   acpi_table_compute_checksum(rsdp,
-                                               ((struct acpi20_table_rsdp *)
-                                                rsdp)->length);
-
-       if (result) {
-               printk(KERN_WARNING "  >>> ERROR: Invalid checksum\n");
-               return -ENODEV;
-       }
-
-       /* Locate and map the System Description table (RSDT/XSDT) */
-
-       if (acpi_table_get_sdt(rsdp))
-               return -ENODEV;
-
+       acpi_initialize_tables(initial_tables, ACPI_MAX_TABLES, 0);
        return 0;
 }
index aa4c695..0a7d7af 100644 (file)
@@ -2,7 +2,6 @@
 # Makefile for all Linux ACPI interpreter subdirectories
 #
 
-obj-y := tbconvrt.o  tbget.o     tbrsdt.o   tbxface.o  \
-        tbgetall.o  tbinstal.o  tbutils.o  tbxfroot.o
+obj-y := tbxface.o tbinstal.o  tbutils.o tbfind.o tbfadt.o
 
 EXTRA_CFLAGS += $(ACPI_CFLAGS)
diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c
deleted file mode 100644 (file)
index d697fcb..0000000
+++ /dev/null
@@ -1,622 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbconvrt - ACPI Table conversion utilities
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * 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,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any 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.
- *
- * NO WARRANTY
- * 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 MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT          ACPI_TABLES
-ACPI_MODULE_NAME("tbconvrt")
-
-/* Local prototypes */
-static void
-acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
-                            u8 register_bit_width,
-                            acpi_physical_address address);
-
-static void
-acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt,
-                     struct fadt_descriptor_rev1 *original_fadt);
-
-static void
-acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt,
-                     struct fadt_descriptor *original_fadt);
-
-u8 acpi_fadt_is_v1;
-ACPI_EXPORT_SYMBOL(acpi_fadt_is_v1)
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_table_count
- *
- * PARAMETERS:  RSDP            - Pointer to the RSDP
- *              RSDT            - Pointer to the RSDT/XSDT
- *
- * RETURN:      The number of tables pointed to by the RSDT or XSDT.
- *
- * DESCRIPTION: Calculate the number of tables.  Automatically handles either
- *              an RSDT or XSDT.
- *
- ******************************************************************************/
-
-u32
-acpi_tb_get_table_count(struct rsdp_descriptor *RSDP,
-                       struct acpi_table_header *RSDT)
-{
-       u32 pointer_size;
-
-       ACPI_FUNCTION_ENTRY();
-
-       /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */
-
-       if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
-               pointer_size = sizeof(u32);
-       } else {
-               pointer_size = sizeof(u64);
-       }
-
-       /*
-        * Determine the number of tables pointed to by the RSDT/XSDT.
-        * This is defined by the ACPI Specification to be the number of
-        * pointers contained within the RSDT/XSDT.  The size of the pointers
-        * is architecture-dependent.
-        */
-       return ((RSDT->length -
-                sizeof(struct acpi_table_header)) / pointer_size);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_convert_to_xsdt
- *
- * PARAMETERS:  table_info      - Info about the RSDT
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Convert an RSDT to an XSDT (internal common format)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info)
-{
-       acpi_size table_size;
-       u32 i;
-       struct xsdt_descriptor *new_table;
-
-       ACPI_FUNCTION_ENTRY();
-
-       /* Compute size of the converted XSDT */
-
-       table_size = ((acpi_size) acpi_gbl_rsdt_table_count * sizeof(u64)) +
-           sizeof(struct acpi_table_header);
-
-       /* Allocate an XSDT */
-
-       new_table = ACPI_ALLOCATE_ZEROED(table_size);
-       if (!new_table) {
-               return (AE_NO_MEMORY);
-       }
-
-       /* Copy the header and set the length */
-
-       ACPI_MEMCPY(new_table, table_info->pointer,
-                   sizeof(struct acpi_table_header));
-       new_table->length = (u32) table_size;
-
-       /* Copy the table pointers */
-
-       for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
-
-               /* RSDT pointers are 32 bits, XSDT pointers are 64 bits */
-
-               if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
-                       ACPI_STORE_ADDRESS(new_table->table_offset_entry[i],
-                                          (ACPI_CAST_PTR
-                                           (struct rsdt_descriptor,
-                                            table_info->pointer))->
-                                          table_offset_entry[i]);
-               } else {
-                       new_table->table_offset_entry[i] =
-                           (ACPI_CAST_PTR(struct xsdt_descriptor,
-                                          table_info->pointer))->
-                           table_offset_entry[i];
-               }
-       }
-
-       /* Delete the original table (either mapped or in a buffer) */
-
-       acpi_tb_delete_single_table(table_info);
-
-       /* Point the table descriptor to the new table */
-
-       table_info->pointer =
-           ACPI_CAST_PTR(struct acpi_table_header, new_table);
-       table_info->length = table_size;
-       table_info->allocation = ACPI_MEM_ALLOCATED;
-
-       return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_init_generic_address
- *
- * PARAMETERS:  new_gas_struct      - GAS struct to be initialized
- *              register_bit_width  - Width of this register
- *              Address             - Address of the register
- *
- * RETURN:      None
- *
- * DESCRIPTION: Initialize a GAS structure.
- *
- ******************************************************************************/
-
-static void
-acpi_tb_init_generic_address(struct acpi_generic_address *new_gas_struct,
-                            u8 register_bit_width,
-                            acpi_physical_address address)
-{
-
-       ACPI_STORE_ADDRESS(new_gas_struct->address, address);
-
-       new_gas_struct->address_space_id = ACPI_ADR_SPACE_SYSTEM_IO;
-       new_gas_struct->register_bit_width = register_bit_width;
-       new_gas_struct->register_bit_offset = 0;
-       new_gas_struct->access_width = 0;
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_convert_fadt1
- *
- * PARAMETERS:  local_fadt      - Pointer to new FADT
- *              original_fadt   - Pointer to old FADT
- *
- * RETURN:      None, populates local_fadt
- *
- * DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format
- *
- ******************************************************************************/
-
-static void
-acpi_tb_convert_fadt1(struct fadt_descriptor *local_fadt,
-                     struct fadt_descriptor_rev1 *original_fadt)
-{
-
-       /* ACPI 1.0 FACS */
-       /* The BIOS stored FADT should agree with Revision 1.0 */
-       acpi_fadt_is_v1 = 1;
-
-       /*
-        * Copy the table header and the common part of the tables.
-        *
-        * The 2.0 table is an extension of the 1.0 table, so the entire 1.0
-        * table can be copied first, then expand some fields to 64 bits.
-        */
-       ACPI_MEMCPY(local_fadt, original_fadt,
-                   sizeof(struct fadt_descriptor_rev1));
-
-       /* Convert table pointers to 64-bit fields */
-
-       ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl,
-                          local_fadt->V1_firmware_ctrl);
-       ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt);
-
-       /*
-        * System Interrupt Model isn't used in ACPI 2.0
-        * (local_fadt->Reserved1 = 0;)
-        */
-
-       /*
-        * This field is set by the OEM to convey the preferred power management
-        * profile to OSPM. It doesn't have any 1.0 equivalence.  Since we don't
-        * know what kind of 32-bit system this is, we will use "unspecified".
-        */
-       local_fadt->prefer_PM_profile = PM_UNSPECIFIED;
-
-       /*
-        * Processor Performance State Control. This is the value OSPM writes to
-        * the SMI_CMD register to assume processor performance state control
-        * responsibility. There isn't any equivalence in 1.0, but as many 1.x
-        * ACPI tables contain _PCT and _PSS we also keep this value, unless
-        * acpi_strict is set.
-        */
-       if (acpi_strict)
-               local_fadt->pstate_cnt = 0;
-
-       /*
-        * Support for the _CST object and C States change notification.
-        * This data item hasn't any 1.0 equivalence so leave it zero.
-        */
-       local_fadt->cst_cnt = 0;
-
-       /*
-        * FADT Rev 2 was an interim FADT released between ACPI 1.0 and ACPI 2.0.
-        * It primarily adds the FADT reset mechanism.
-        */
-       if ((original_fadt->revision == 2) &&
-           (original_fadt->length ==
-            sizeof(struct fadt_descriptor_rev2_minus))) {
-               /*
-                * Grab the entire generic address struct, plus the 1-byte reset value
-                * that immediately follows.
-                */
-               ACPI_MEMCPY(&local_fadt->reset_register,
-                           &(ACPI_CAST_PTR(struct fadt_descriptor_rev2_minus,
-                                           original_fadt))->reset_register,
-                           sizeof(struct acpi_generic_address) + 1);
-       } else {
-               /*
-                * Since there isn't any equivalence in 1.0 and since it is highly
-                * likely that a 1.0 system has legacy support.
-                */
-               local_fadt->iapc_boot_arch = BAF_LEGACY_DEVICES;
-       }
-
-       /*
-        * Convert the V1.0 block addresses to V2.0 GAS structures
-        */
-       acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk,
-                                    local_fadt->pm1_evt_len,
-                                    (acpi_physical_address) local_fadt->
-                                    V1_pm1a_evt_blk);
-       acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk,
-                                    local_fadt->pm1_evt_len,
-                                    (acpi_physical_address) local_fadt->
-                                    V1_pm1b_evt_blk);
-       acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk,
-                                    local_fadt->pm1_cnt_len,
-                                    (acpi_physical_address) local_fadt->
-                                    V1_pm1a_cnt_blk);
-       acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk,
-                                    local_fadt->pm1_cnt_len,
-                                    (acpi_physical_address) local_fadt->
-                                    V1_pm1b_cnt_blk);
-       acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk,
-                                    local_fadt->pm2_cnt_len,
-                                    (acpi_physical_address) local_fadt->
-                                    V1_pm2_cnt_blk);
-       acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk,
-                                    local_fadt->pm_tm_len,
-                                    (acpi_physical_address) local_fadt->
-                                    V1_pm_tmr_blk);
-       acpi_tb_init_generic_address(&local_fadt->xgpe0_blk, 0,
-                                    (acpi_physical_address) local_fadt->
-                                    V1_gpe0_blk);
-       acpi_tb_init_generic_address(&local_fadt->xgpe1_blk, 0,
-                                    (acpi_physical_address) local_fadt->
-                                    V1_gpe1_blk);
-
-       /* Create separate GAS structs for the PM1 Enable registers */
-
-       acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
-                                    (u8) ACPI_DIV_2(acpi_gbl_FADT->
-                                                    pm1_evt_len),
-                                    (acpi_physical_address)
-                                    (local_fadt->xpm1a_evt_blk.address +
-                                     ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len)));
-
-       /* PM1B is optional; leave null if not present */
-
-       if (local_fadt->xpm1b_evt_blk.address) {
-               acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
-                                            (u8) ACPI_DIV_2(acpi_gbl_FADT->
-                                                            pm1_evt_len),
-                                            (acpi_physical_address)
-                                            (local_fadt->xpm1b_evt_blk.
-                                             address +
-                                             ACPI_DIV_2(acpi_gbl_FADT->
-                                                        pm1_evt_len)));
-       }
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_convert_fadt2
- *
- * PARAMETERS:  local_fadt      - Pointer to new FADT
- *              original_fadt   - Pointer to old FADT
- *
- * RETURN:      None, populates local_fadt
- *
- * DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format.
- *              Handles optional "X" fields.
- *
- ******************************************************************************/
-
-static void
-acpi_tb_convert_fadt2(struct fadt_descriptor *local_fadt,
-                     struct fadt_descriptor *original_fadt)
-{
-
-       /* We have an ACPI 2.0 FADT but we must copy it to our local buffer */
-
-       ACPI_MEMCPY(local_fadt, original_fadt, sizeof(struct fadt_descriptor));
-
-       /*
-        * "X" fields are optional extensions to the original V1.0 fields, so
-        * we must selectively expand V1.0 fields if the corresponding X field
-        * is zero.
-        */
-       if (!(local_fadt->xfirmware_ctrl)) {
-               ACPI_STORE_ADDRESS(local_fadt->xfirmware_ctrl,
-                                  local_fadt->V1_firmware_ctrl);
-       }
-
-       if (!(local_fadt->Xdsdt)) {
-               ACPI_STORE_ADDRESS(local_fadt->Xdsdt, local_fadt->V1_dsdt);
-       }
-
-       if (!(local_fadt->xpm1a_evt_blk.address)) {
-               acpi_tb_init_generic_address(&local_fadt->xpm1a_evt_blk,
-                                            local_fadt->pm1_evt_len,
-                                            (acpi_physical_address)
-                                            local_fadt->V1_pm1a_evt_blk);
-       }
-
-       if (!(local_fadt->xpm1b_evt_blk.address)) {
-               acpi_tb_init_generic_address(&local_fadt->xpm1b_evt_blk,
-                                            local_fadt->pm1_evt_len,
-                                            (acpi_physical_address)
-                                            local_fadt->V1_pm1b_evt_blk);
-       }
-
-       if (!(local_fadt->xpm1a_cnt_blk.address)) {
-               acpi_tb_init_generic_address(&local_fadt->xpm1a_cnt_blk,
-                                            local_fadt->pm1_cnt_len,
-                                            (acpi_physical_address)
-                                            local_fadt->V1_pm1a_cnt_blk);
-       }
-
-       if (!(local_fadt->xpm1b_cnt_blk.address)) {
-               acpi_tb_init_generic_address(&local_fadt->xpm1b_cnt_blk,
-                                            local_fadt->pm1_cnt_len,
-                                            (acpi_physical_address)
-                                            local_fadt->V1_pm1b_cnt_blk);
-       }
-
-       if (!(local_fadt->xpm2_cnt_blk.address)) {
-               acpi_tb_init_generic_address(&local_fadt->xpm2_cnt_blk,
-                                            local_fadt->pm2_cnt_len,
-                                            (acpi_physical_address)
-                                            local_fadt->V1_pm2_cnt_blk);
-       }
-
-       if (!(local_fadt->xpm_tmr_blk.address)) {
-               acpi_tb_init_generic_address(&local_fadt->xpm_tmr_blk,
-                                            local_fadt->pm_tm_len,
-                                            (acpi_physical_address)
-                                            local_fadt->V1_pm_tmr_blk);
-       }
-
-       if (!(local_fadt->xgpe0_blk.address)) {
-               acpi_tb_init_generic_address(&local_fadt->xgpe0_blk,
-                                            0,
-                                            (acpi_physical_address)
-                                            local_fadt->V1_gpe0_blk);
-       }
-
-       if (!(local_fadt->xgpe1_blk.address)) {
-               acpi_tb_init_generic_address(&local_fadt->xgpe1_blk,
-                                            0,
-                                            (acpi_physical_address)
-                                            local_fadt->V1_gpe1_blk);
-       }
-
-       /* Create separate GAS structs for the PM1 Enable registers */
-
-       acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
-                                    (u8) ACPI_DIV_2(acpi_gbl_FADT->
-                                                    pm1_evt_len),
-                                    (acpi_physical_address)
-                                    (local_fadt->xpm1a_evt_blk.address +
-                                     ACPI_DIV_2(acpi_gbl_FADT->pm1_evt_len)));
-
-       acpi_gbl_xpm1a_enable.address_space_id =
-           local_fadt->xpm1a_evt_blk.address_space_id;
-
-       /* PM1B is optional; leave null if not present */
-
-       if (local_fadt->xpm1b_evt_blk.address) {
-               acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
-                                            (u8) ACPI_DIV_2(acpi_gbl_FADT->
-                                                            pm1_evt_len),
-                                            (acpi_physical_address)
-                                            (local_fadt->xpm1b_evt_blk.
-                                             address +
-                                             ACPI_DIV_2(acpi_gbl_FADT->
-                                                        pm1_evt_len)));
-
-               acpi_gbl_xpm1b_enable.address_space_id =
-                   local_fadt->xpm1b_evt_blk.address_space_id;
-       }
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_convert_table_fadt
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Converts a BIOS supplied ACPI 1.0 FADT to a local
- *              ACPI 2.0 FADT. If the BIOS supplied a 2.0 FADT then it is simply
- *              copied to the local FADT.  The ACPI CA software uses this
- *              local FADT. Thus a significant amount of special #ifdef
- *              type codeing is saved.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_convert_table_fadt(void)
-{
-       struct fadt_descriptor *local_fadt;
-       struct acpi_table_desc *table_desc;
-
-       ACPI_FUNCTION_TRACE(tb_convert_table_fadt);
-
-       /*
-        * acpi_gbl_FADT is valid. Validate the FADT length. The table must be
-        * at least as long as the version 1.0 FADT
-        */
-       if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor_rev1)) {
-               ACPI_ERROR((AE_INFO, "FADT is invalid, too short: 0x%X",
-                           acpi_gbl_FADT->length));
-               return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
-       }
-
-       /* Allocate buffer for the ACPI 2.0(+) FADT */
-
-       local_fadt = ACPI_ALLOCATE_ZEROED(sizeof(struct fadt_descriptor));
-       if (!local_fadt) {
-               return_ACPI_STATUS(AE_NO_MEMORY);
-       }
-
-       if (acpi_gbl_FADT->revision >= FADT2_REVISION_ID) {
-               if (acpi_gbl_FADT->length < sizeof(struct fadt_descriptor)) {
-
-                       /* Length is too short to be a V2.0 table */
-
-                       ACPI_WARNING((AE_INFO,
-                                     "Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table",
-                                     acpi_gbl_FADT->length,
-                                     acpi_gbl_FADT->revision));
-
-                       acpi_tb_convert_fadt1(local_fadt,
-                                             (void *)acpi_gbl_FADT);
-               } else {
-                       /* Valid V2.0 table */
-
-                       acpi_tb_convert_fadt2(local_fadt, acpi_gbl_FADT);
-               }
-       } else {
-               /* Valid V1.0 table */
-
-               acpi_tb_convert_fadt1(local_fadt, (void *)acpi_gbl_FADT);
-       }
-
-       /* Global FADT pointer will point to the new common V2.0 FADT */
-
-       acpi_gbl_FADT = local_fadt;
-       acpi_gbl_FADT->length = sizeof(struct fadt_descriptor);
-
-       /* Free the original table */
-
-       table_desc = acpi_gbl_table_lists[ACPI_TABLE_ID_FADT].next;
-       acpi_tb_delete_single_table(table_desc);
-
-       /* Install the new table */
-
-       table_desc->pointer =
-           ACPI_CAST_PTR(struct acpi_table_header, acpi_gbl_FADT);
-       table_desc->allocation = ACPI_MEM_ALLOCATED;
-       table_desc->length = sizeof(struct fadt_descriptor);
-
-       /* Dump the entire FADT */
-
-       ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
-                         "Hex dump of common internal FADT, size %d (%X)\n",
-                         acpi_gbl_FADT->length, acpi_gbl_FADT->length));
-
-       ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_FADT),
-                        acpi_gbl_FADT->length);
-
-       return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_build_common_facs
- *
- * PARAMETERS:  table_info      - Info for currently installed FACS
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Convert ACPI 1.0 and ACPI 2.0 FACS to a common internal
- *              table format.
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info)
-{
-
-       ACPI_FUNCTION_TRACE(tb_build_common_facs);
-
-       /* Absolute minimum length is 24, but the ACPI spec says 64 */
-
-       if (acpi_gbl_FACS->length < 24) {
-               ACPI_ERROR((AE_INFO, "Invalid FACS table length: 0x%X",
-                           acpi_gbl_FACS->length));
-               return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
-       }
-
-       if (acpi_gbl_FACS->length < 64) {
-               ACPI_WARNING((AE_INFO,
-                             "FACS is shorter than the ACPI specification allows: 0x%X, using anyway",
-                             acpi_gbl_FACS->length));
-       }
-
-       /* Copy fields to the new FACS */
-
-       acpi_gbl_common_fACS.global_lock = &(acpi_gbl_FACS->global_lock);
-
-       if ((acpi_gbl_RSDP->revision < 2) ||
-           (acpi_gbl_FACS->length < 32) ||
-           (!(acpi_gbl_FACS->xfirmware_waking_vector))) {
-
-               /* ACPI 1.0 FACS or short table or optional X_ field is zero */
-
-               acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR(u64,
-                                                                           &
-                                                                           (acpi_gbl_FACS->
-                                                                            firmware_waking_vector));
-               acpi_gbl_common_fACS.vector_width = 32;
-       } else {
-               /* ACPI 2.0 FACS with valid X_ field */
-
-               acpi_gbl_common_fACS.firmware_waking_vector =
-                   &acpi_gbl_FACS->xfirmware_waking_vector;
-               acpi_gbl_common_fACS.vector_width = 64;
-       }
-
-       return_ACPI_STATUS(AE_OK);
-}
diff --git a/drivers/acpi/tables/tbfadt.c b/drivers/acpi/tables/tbfadt.c
new file mode 100644 (file)
index 0000000..807c711
--- /dev/null
@@ -0,0 +1,434 @@
+/******************************************************************************
+ *
+ * Module Name: tbfadt   - FADT table utilities
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2007, R. Byron Moore
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any 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.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/actables.h>
+
+#define _COMPONENT          ACPI_TABLES
+ACPI_MODULE_NAME("tbfadt")
+
+/* Local prototypes */
+static void inline
+acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
+                            u8 bit_width, u64 address);
+
+static void acpi_tb_convert_fadt(void);
+
+static void acpi_tb_validate_fadt(void);
+
+/* Table for conversion of FADT to common internal format and FADT validation */
+
+typedef struct acpi_fadt_info {
+       char *name;
+       u8 target;
+       u8 source;
+       u8 length;
+       u8 type;
+
+} acpi_fadt_info;
+
+#define ACPI_FADT_REQUIRED          1
+#define ACPI_FADT_SEPARATE_LENGTH   2
+
+static struct acpi_fadt_info fadt_info_table[] = {
+       {"Pm1aEventBlock", ACPI_FADT_OFFSET(xpm1a_event_block),
+        ACPI_FADT_OFFSET(pm1a_event_block),
+        ACPI_FADT_OFFSET(pm1_event_length), ACPI_FADT_REQUIRED},
+
+       {"Pm1bEventBlock", ACPI_FADT_OFFSET(xpm1b_event_block),
+        ACPI_FADT_OFFSET(pm1b_event_block),
+        ACPI_FADT_OFFSET(pm1_event_length), 0},
+
+       {"Pm1aControlBlock", ACPI_FADT_OFFSET(xpm1a_control_block),
+        ACPI_FADT_OFFSET(pm1a_control_block),
+        ACPI_FADT_OFFSET(pm1_control_length), ACPI_FADT_REQUIRED},
+
+       {"Pm1bControlBlock", ACPI_FADT_OFFSET(xpm1b_control_block),
+        ACPI_FADT_OFFSET(pm1b_control_block),
+        ACPI_FADT_OFFSET(pm1_control_length), 0},
+
+       {"Pm2ControlBlock", ACPI_FADT_OFFSET(xpm2_control_block),
+        ACPI_FADT_OFFSET(pm2_control_block),
+        ACPI_FADT_OFFSET(pm2_control_length), ACPI_FADT_SEPARATE_LENGTH},
+
+       {"PmTimerBlock", ACPI_FADT_OFFSET(xpm_timer_block),
+        ACPI_FADT_OFFSET(pm_timer_block),
+        ACPI_FADT_OFFSET(pm_timer_length), ACPI_FADT_REQUIRED},
+
+       {"Gpe0Block", ACPI_FADT_OFFSET(xgpe0_block),
+        ACPI_FADT_OFFSET(gpe0_block),
+        ACPI_FADT_OFFSET(gpe0_block_length), ACPI_FADT_SEPARATE_LENGTH},
+
+       {"Gpe1Block", ACPI_FADT_OFFSET(xgpe1_block),
+        ACPI_FADT_OFFSET(gpe1_block),
+        ACPI_FADT_OFFSET(gpe1_block_length), ACPI_FADT_SEPARATE_LENGTH}
+};
+
+#define ACPI_FADT_INFO_ENTRIES        (sizeof (fadt_info_table) / sizeof (struct acpi_fadt_info))
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_init_generic_address
+ *
+ * PARAMETERS:  generic_address     - GAS struct to be initialized
+ *              bit_width           - Width of this register
+ *              Address             - Address of the register
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Initialize a Generic Address Structure (GAS)
+ *              See the ACPI specification for a full description and
+ *              definition of this structure.
+ *
+ ******************************************************************************/
+
+static void inline
+acpi_tb_init_generic_address(struct acpi_generic_address *generic_address,
+                            u8 bit_width, u64 address)
+{
+
+       /*
+        * The 64-bit Address field is non-aligned in the byte packed
+        * GAS struct.
+        */
+       ACPI_MOVE_64_TO_64(&generic_address->address, &address);
+
+       /* All other fields are byte-wide */
+
+       generic_address->space_id = ACPI_ADR_SPACE_SYSTEM_IO;
+       generic_address->bit_width = bit_width;
+       generic_address->bit_offset = 0;
+       generic_address->access_width = 0;
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_parse_fadt
+ *
+ * PARAMETERS:  table_index         - Index for the FADT
+ *              Flags               - Flags
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Initialize the FADT, DSDT and FACS tables
+ *              (FADT contains the addresses of the DSDT and FACS)
+ *
+ ******************************************************************************/
+
+void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags)
+{
+       u32 length;
+       struct acpi_table_header *table;
+
+       /*
+        * The FADT has multiple versions with different lengths,
+        * and it contains pointers to both the DSDT and FACS tables.
+        *
+        * Get a local copy of the FADT and convert it to a common format
+        * Map entire FADT, assumed to be smaller than one page.
+        */
+       length = acpi_gbl_root_table_list.tables[table_index].length;
+
+       table =
+           acpi_os_map_memory(acpi_gbl_root_table_list.tables[table_index].
+                              address, length);
+       if (!table) {
+               return;
+       }
+
+       /*
+        * Validate the FADT checksum before we copy the table. Ignore
+        * checksum error as we want to try to get the DSDT and FACS.
+        */
+       (void)acpi_tb_verify_checksum(table, length);
+
+       /* Obtain a local copy of the FADT in common ACPI 2.0+ format */
+
+       acpi_tb_create_local_fadt(table, length);
+
+       /* All done with the real FADT, unmap it */
+
+       acpi_os_unmap_memory(table, length);
+
+       /* Obtain the DSDT and FACS tables via their addresses within the FADT */
+
+       acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xdsdt,
+                             flags, ACPI_SIG_DSDT, ACPI_TABLE_INDEX_DSDT);
+
+       acpi_tb_install_table((acpi_physical_address) acpi_gbl_FADT.Xfacs,
+                             flags, ACPI_SIG_FACS, ACPI_TABLE_INDEX_FACS);
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_create_local_fadt
+ *
+ * PARAMETERS:  Table               - Pointer to BIOS FADT
+ *              Length              - Length of the table
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Get a local copy of the FADT and convert it to a common format.
+ *              Performs validation on some important FADT fields.
+ *
+ ******************************************************************************/
+
+void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length)
+{
+
+       /*
+        * Check if the FADT is larger than what we know about (ACPI 2.0 version).
+        * Truncate the table, but make some noise.
+        */
+       if (length > sizeof(struct acpi_table_fadt)) {
+               ACPI_WARNING((AE_INFO,
+                             "FADT (revision %u) is longer than ACPI 2.0 version, truncating length 0x%X to 0x%zX",
+                             table->revision, (unsigned)length,
+                             sizeof(struct acpi_table_fadt)));
+       }
+
+       /* Copy the entire FADT locally. Zero first for tb_convert_fadt */
+
+       ACPI_MEMSET(&acpi_gbl_FADT, 0, sizeof(struct acpi_table_fadt));
+
+       ACPI_MEMCPY(&acpi_gbl_FADT, table,
+                   ACPI_MIN(length, sizeof(struct acpi_table_fadt)));
+
+       /*
+        * 1) Convert the local copy of the FADT to the common internal format
+        * 2) Validate some of the important values within the FADT
+        */
+       acpi_tb_convert_fadt();
+       acpi_tb_validate_fadt();
+}
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_convert_fadt
+ *
+ * PARAMETERS:  None, uses acpi_gbl_FADT
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Converts all versions of the FADT to a common internal format.
+ *              -> Expand all 32-bit addresses to 64-bit.
+ *
+ * NOTE:        acpi_gbl_FADT must be of size (struct acpi_table_fadt),
+ *              and must contain a copy of the actual FADT.
+ *
+ * ACPICA will use the "X" fields of the FADT for all addresses.
+ *
+ * "X" fields are optional extensions to the original V1.0 fields. Even if
+ * they are present in the structure, they can be optionally not used by
+ * setting them to zero. Therefore, we must selectively expand V1.0 fields
+ * if the corresponding X field is zero.
+ *
+ * For ACPI 1.0 FADTs, all address fields are expanded to the corresponding
+ * "X" fields.
+ *
+ * For ACPI 2.0 FADTs, any "X" fields that are NULL are filled in by
+ * expanding the corresponding ACPI 1.0 field.
+ *
+ ******************************************************************************/
+
+static void acpi_tb_convert_fadt(void)
+{
+       u8 pm1_register_length;
+       struct acpi_generic_address *target;
+       acpi_native_uint i;
+
+       /* Update the local FADT table header length */
+
+       acpi_gbl_FADT.header.length = sizeof(struct acpi_table_fadt);
+
+       /* Expand the 32-bit FACS and DSDT addresses to 64-bit as necessary */
+
+       if (!acpi_gbl_FADT.Xfacs) {
+               acpi_gbl_FADT.Xfacs = (u64) acpi_gbl_FADT.facs;
+       }
+
+       if (!acpi_gbl_FADT.Xdsdt) {
+               acpi_gbl_FADT.Xdsdt = (u64) acpi_gbl_FADT.dsdt;
+       }
+
+       /*
+        * Expand the 32-bit V1.0 addresses to the 64-bit "X" generic address
+        * structures as necessary.
+        */
+       for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+               target =
+                   ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
+                                fadt_info_table[i].target);
+
+               /* Expand only if the X target is null */
+
+               if (!target->address) {
+                       acpi_tb_init_generic_address(target,
+                                                    *ACPI_ADD_PTR(u8,
+                                                                  &acpi_gbl_FADT,
+                                                                  fadt_info_table
+                                                                  [i].length),
+                                                    (u64) * ACPI_ADD_PTR(u32,
+                                                                         &acpi_gbl_FADT,
+                                                                         fadt_info_table
+                                                                         [i].
+                                                                         source));
+               }
+       }
+
+       /*
+        * Calculate separate GAS structs for the PM1 Enable registers.
+        * These addresses do not appear (directly) in the FADT, so it is
+        * useful to calculate them once, here.
+        *
+        * The PM event blocks are split into two register blocks, first is the
+        * PM Status Register block, followed immediately by the PM Enable Register
+        * block. Each is of length (pm1_event_length/2)
+        */
+       pm1_register_length = (u8) ACPI_DIV_2(acpi_gbl_FADT.pm1_event_length);
+
+       /* The PM1A register block is required */
+
+       acpi_tb_init_generic_address(&acpi_gbl_xpm1a_enable,
+                                    pm1_register_length,
+                                    (acpi_gbl_FADT.xpm1a_event_block.address +
+                                     pm1_register_length));
+       /* Don't forget to copy space_id of the GAS */
+       acpi_gbl_xpm1a_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+
+       /* The PM1B register block is optional, ignore if not present */
+
+       if (acpi_gbl_FADT.xpm1b_event_block.address) {
+               acpi_tb_init_generic_address(&acpi_gbl_xpm1b_enable,
+                                            pm1_register_length,
+                                            (acpi_gbl_FADT.xpm1b_event_block.
+                                             address + pm1_register_length));
+               /* Don't forget to copy space_id of the GAS */
+               acpi_gbl_xpm1b_enable.space_id = acpi_gbl_FADT.xpm1a_event_block.space_id;
+
+       }
+}
+
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_validate_fadt
+ *
+ * PARAMETERS:  Table           - Pointer to the FADT to be validated
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Validate various important fields within the FADT. If a problem
+ *              is found, issue a message, but no status is returned.
+ *              Used by both the table manager and the disassembler.
+ *
+ * Possible additional checks:
+ * (acpi_gbl_FADT.pm1_event_length >= 4)
+ * (acpi_gbl_FADT.pm1_control_length >= 2)
+ * (acpi_gbl_FADT.pm_timer_length >= 4)
+ * Gpe block lengths must be multiple of 2
+ *
+ ******************************************************************************/
+
+static void acpi_tb_validate_fadt(void)
+{
+       u32 *address32;
+       struct acpi_generic_address *address64;
+       u8 length;
+       acpi_native_uint i;
+
+       /* Examine all of the 64-bit extended address fields (X fields) */
+
+       for (i = 0; i < ACPI_FADT_INFO_ENTRIES; i++) {
+
+               /* Generate pointers to the 32-bit and 64-bit addresses and get the length */
+
+               address64 =
+                   ACPI_ADD_PTR(struct acpi_generic_address, &acpi_gbl_FADT,
+                                fadt_info_table[i].target);
+               address32 =
+                   ACPI_ADD_PTR(u32, &acpi_gbl_FADT,
+                                fadt_info_table[i].source);
+               length =
+                   *ACPI_ADD_PTR(u8, &acpi_gbl_FADT,
+                                 fadt_info_table[i].length);
+
+               if (fadt_info_table[i].type & ACPI_FADT_REQUIRED) {
+                       /*
+                        * Field is required (Pm1a_event, Pm1a_control, pm_timer).
+                        * Both the address and length must be non-zero.
+                        */
+                       if (!address64->address || !length) {
+                               ACPI_ERROR((AE_INFO,
+                                           "Required field \"%s\" has zero address and/or length: %8.8X%8.8X/%X",
+                                           fadt_info_table[i].name,
+                                           ACPI_FORMAT_UINT64(address64->
+                                                              address),
+                                           length));
+                       }
+               } else if (fadt_info_table[i].type & ACPI_FADT_SEPARATE_LENGTH) {
+                       /*
+                        * Field is optional (PM2Control, GPE0, GPE1) AND has its own
+                        * length field. If present, both the address and length must be valid.
+                        */
+                       if ((address64->address && !length)
+                           || (!address64->address && length)) {
+                               ACPI_WARNING((AE_INFO,
+                                             "Optional field \"%s\" has zero address or length: %8.8X%8.8X/%X",
+                                             fadt_info_table[i].name,
+                                             ACPI_FORMAT_UINT64(address64->
+                                                                address),
+                                             length));
+                       }
+               }
+
+               /* If both 32- and 64-bit addresses are valid (non-zero), they must match */
+
+               if (address64->address && *address32 &&
+                   (address64->address != (u64) * address32)) {
+                       ACPI_ERROR((AE_INFO,
+                                   "32/64X address mismatch in \"%s\": [%8.8X] [%8.8X%8.8X], using 64X",
+                                   fadt_info_table[i].name, *address32,
+                                   ACPI_FORMAT_UINT64(address64->address)));
+               }
+       }
+}
diff --git a/drivers/acpi/tables/tbfind.c b/drivers/acpi/tables/tbfind.c
new file mode 100644 (file)
index 0000000..058c064
--- /dev/null
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Module Name: tbfind   - find table
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2007, R. Byron Moore
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any 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.
+ *
+ * NO WARRANTY
+ * 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 MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#include <acpi/acpi.h>
+#include <acpi/actables.h>
+
+#define _COMPONENT          ACPI_TABLES
+ACPI_MODULE_NAME("tbfind")
+
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_find_table
+ *
+ * PARAMETERS:  Signature           - String with ACPI table signature
+ *              oem_id              - String with the table OEM ID
+ *              oem_table_id        - String with the OEM Table ID
+ *              table_index         - Where the table index is returned
+ *
+ * RETURN:      Status and table index
+ *
+ * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the
+ *              Signature, OEM ID and OEM Table ID. Returns an index that can
+ *              be used to get the table header or entire table.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_tb_find_table(char *signature,
+                  char *oem_id,
+                  char *oem_table_id, acpi_native_uint * table_index)
+{
+       acpi_native_uint i;
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE(tb_find_table);
+
+       for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+               if (ACPI_MEMCMP(&(acpi_gbl_root_table_list.tables[i].signature),
+                               signature, ACPI_NAME_SIZE)) {
+
+                       /* Not the requested table */
+
+                       continue;
+               }
+
+               /* Table with matching signature has been found */
+
+               if (!acpi_gbl_root_table_list.tables[i].pointer) {
+
+                       /* Table is not currently mapped, map it */
+
+                       status =
+                           acpi_tb_verify_table(&acpi_gbl_root_table_list.
+                                                tables[i]);
+                       if (ACPI_FAILURE(status)) {
+                               return_ACPI_STATUS(status);
+                       }
+
+                       if (!acpi_gbl_root_table_list.tables[i].pointer) {
+                               continue;
+                       }
+               }
+
+               /* Check for table match on all IDs */
+
+               if (!ACPI_MEMCMP
+                   (acpi_gbl_root_table_list.tables[i].pointer->signature,
+                    signature, ACPI_NAME_SIZE) && (!oem_id[0]
+                                                   ||
+                                                   !ACPI_MEMCMP
+                                                   (acpi_gbl_root_table_list.
+                                                    tables[i].pointer->oem_id,
+                                                    oem_id, ACPI_OEM_ID_SIZE))
+                   && (!oem_table_id[0]
+                       || !ACPI_MEMCMP(acpi_gbl_root_table_list.tables[i].
+                                       pointer->oem_table_id, oem_table_id,
+                                       ACPI_OEM_TABLE_ID_SIZE))) {
+                       *table_index = i;
+
+                       ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
+                                         "Found table [%4.4s]\n", signature));
+                       return_ACPI_STATUS(AE_OK);
+               }
+       }
+
+       return_ACPI_STATUS(AE_NOT_FOUND);
+}
diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
deleted file mode 100644 (file)
index 11e2d44..0000000
+++ /dev/null
@@ -1,471 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbget - ACPI Table get* routines
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * 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,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any 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.
- *
- * NO WARRANTY
- * 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 MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT          ACPI_TABLES
-ACPI_MODULE_NAME("tbget")
-
-/* Local prototypes */
-static acpi_status
-acpi_tb_get_this_table(struct acpi_pointer *address,
-                      struct acpi_table_header *header,
-                      struct acpi_table_desc *table_info);
-
-static acpi_status
-acpi_tb_table_override(struct acpi_table_header *header,
-                      struct acpi_table_desc *table_info);
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_table
- *
- * PARAMETERS:  Address             - Address of table to retrieve.  Can be
- *                                    Logical or Physical
- *              table_info          - Where table info is returned
- *
- * RETURN:      None
- *
- * DESCRIPTION: Get entire table of unknown size.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table(struct acpi_pointer *address,
-                 struct acpi_table_desc *table_info)
-{
-       acpi_status status;
-       struct acpi_table_header header;
-
-       ACPI_FUNCTION_TRACE(tb_get_table);
-
-       /* Get the header in order to get signature and table size */
-
-       status = acpi_tb_get_table_header(address, &header);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /* Get the entire table */
-
-       status = acpi_tb_get_table_body(address, &header, table_info);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Could not get ACPI table (size %X)",
-                               header.length));
-               return_ACPI_STATUS(status);
-       }
-
-       return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_table_header
- *
- * PARAMETERS:  Address             - Address of table to retrieve.  Can be
- *                                    Logical or Physical
- *              return_header       - Where the table header is returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Get an ACPI table header.  Works in both physical or virtual
- *              addressing mode.  Works with both physical or logical pointers.
- *              Table is either copied or mapped, depending on the pointer
- *              type and mode of the processor.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_header(struct acpi_pointer *address,
-                        struct acpi_table_header *return_header)
-{
-       acpi_status status = AE_OK;
-       struct acpi_table_header *header = NULL;
-
-       ACPI_FUNCTION_TRACE(tb_get_table_header);
-
-       /*
-        * Flags contains the current processor mode (Virtual or Physical
-        * addressing) The pointer_type is either Logical or Physical
-        */
-       switch (address->pointer_type) {
-       case ACPI_PHYSMODE_PHYSPTR:
-       case ACPI_LOGMODE_LOGPTR:
-
-               /* Pointer matches processor mode, copy the header */
-
-               ACPI_MEMCPY(return_header, address->pointer.logical,
-                           sizeof(struct acpi_table_header));
-               break;
-
-       case ACPI_LOGMODE_PHYSPTR:
-
-               /* Create a logical address for the physical pointer */
-
-               status = acpi_os_map_memory(address->pointer.physical,
-                                           sizeof(struct acpi_table_header),
-                                           (void *)&header);
-               if (ACPI_FAILURE(status)) {
-                       ACPI_ERROR((AE_INFO,
-                                   "Could not map memory at %8.8X%8.8X for table header",
-                                   ACPI_FORMAT_UINT64(address->pointer.
-                                                      physical)));
-                       return_ACPI_STATUS(status);
-               }
-
-               /* Copy header and delete mapping */
-
-               ACPI_MEMCPY(return_header, header,
-                           sizeof(struct acpi_table_header));
-               acpi_os_unmap_memory(header, sizeof(struct acpi_table_header));
-               break;
-
-       default:
-
-               ACPI_ERROR((AE_INFO, "Invalid address flags %X",
-                           address->pointer_type));
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Table Signature: [%4.4s]\n",
-                         return_header->signature));
-
-       return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_table_body
- *
- * PARAMETERS:  Address             - Address of table to retrieve.  Can be
- *                                    Logical or Physical
- *              Header              - Header of the table to retrieve
- *              table_info          - Where the table info is returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Get an entire ACPI table with support to allow the host OS to
- *              replace the table with a newer version (table override.)
- *              Works in both physical or virtual
- *              addressing mode.  Works with both physical or logical pointers.
- *              Table is either copied or mapped, depending on the pointer
- *              type and mode of the processor.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_body(struct acpi_pointer *address,
-                      struct acpi_table_header *header,
-                      struct acpi_table_desc *table_info)
-{
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE(tb_get_table_body);
-
-       if (!table_info || !address) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
-       /* Attempt table override. */
-
-       status = acpi_tb_table_override(header, table_info);
-       if (ACPI_SUCCESS(status)) {
-
-               /* Table was overridden by the host OS */
-
-               return_ACPI_STATUS(status);
-       }
-
-       /* No override, get the original table */
-
-       status = acpi_tb_get_this_table(address, header, table_info);
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_table_override
- *
- * PARAMETERS:  Header              - Pointer to table header
- *              table_info          - Return info if table is overridden
- *
- * RETURN:      None
- *
- * DESCRIPTION: Attempts override of current table with a new one if provided
- *              by the host OS.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_table_override(struct acpi_table_header *header,
-                      struct acpi_table_desc *table_info)
-{
-       struct acpi_table_header *new_table;
-       acpi_status status;
-       struct acpi_pointer address;
-
-       ACPI_FUNCTION_TRACE(tb_table_override);
-
-       /*
-        * The OSL will examine the header and decide whether to override this
-        * table.  If it decides to override, a table will be returned in new_table,
-        * which we will then copy.
-        */
-       status = acpi_os_table_override(header, &new_table);
-       if (ACPI_FAILURE(status)) {
-
-               /* Some severe error from the OSL, but we basically ignore it */
-
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Could not override ACPI table"));
-               return_ACPI_STATUS(status);
-       }
-
-       if (!new_table) {
-
-               /* No table override */
-
-               return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-       }
-
-       /*
-        * We have a new table to override the old one.  Get a copy of
-        * the new one.  We know that the new table has a logical pointer.
-        */
-       address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
-       address.pointer.logical = new_table;
-
-       status = acpi_tb_get_this_table(&address, new_table, table_info);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status, "Could not copy ACPI table"));
-               return_ACPI_STATUS(status);
-       }
-
-       /* Copy the table info */
-
-       ACPI_INFO((AE_INFO, "Table [%4.4s] replaced by host OS",
-                  table_info->pointer->signature));
-
-       return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_this_table
- *
- * PARAMETERS:  Address             - Address of table to retrieve.  Can be
- *                                    Logical or Physical
- *              Header              - Header of the table to retrieve
- *              table_info          - Where the table info is returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Get an entire ACPI table.  Works in both physical or virtual
- *              addressing mode.  Works with both physical or logical pointers.
- *              Table is either copied or mapped, depending on the pointer
- *              type and mode of the processor.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_this_table(struct acpi_pointer *address,
-                      struct acpi_table_header *header,
-                      struct acpi_table_desc *table_info)
-{
-       struct acpi_table_header *full_table = NULL;
-       u8 allocation;
-       acpi_status status = AE_OK;
-
-       ACPI_FUNCTION_TRACE(tb_get_this_table);
-
-       /* Validate minimum length */
-
-       if (header->length < sizeof(struct acpi_table_header)) {
-               ACPI_ERROR((AE_INFO,
-                           "Table length (%X) is smaller than minimum (%zX)",
-                           header->length, sizeof(struct acpi_table_header)));
-
-               return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
-       }
-
-       /*
-        * Flags contains the current processor mode (Virtual or Physical
-        * addressing) The pointer_type is either Logical or Physical
-        */
-       switch (address->pointer_type) {
-       case ACPI_PHYSMODE_PHYSPTR:
-       case ACPI_LOGMODE_LOGPTR:
-
-               /* Pointer matches processor mode, copy the table to a new buffer */
-
-               full_table = ACPI_ALLOCATE(header->length);
-               if (!full_table) {
-                       ACPI_ERROR((AE_INFO,
-                                   "Could not allocate table memory for [%4.4s] length %X",
-                                   header->signature, header->length));
-                       return_ACPI_STATUS(AE_NO_MEMORY);
-               }
-
-               /* Copy the entire table (including header) to the local buffer */
-
-               ACPI_MEMCPY(full_table, address->pointer.logical,
-                           header->length);
-
-               /* Save allocation type */
-
-               allocation = ACPI_MEM_ALLOCATED;
-               break;
-
-       case ACPI_LOGMODE_PHYSPTR:
-
-               /*
-                * Just map the table's physical memory
-                * into our address space.
-                */
-               status = acpi_os_map_memory(address->pointer.physical,
-                                           (acpi_size) header->length,
-                                           ACPI_CAST_PTR(void, &full_table));
-               if (ACPI_FAILURE(status)) {
-                       ACPI_ERROR((AE_INFO,
-                                   "Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X",
-                                   header->signature,
-                                   ACPI_FORMAT_UINT64(address->pointer.
-                                                      physical),
-                                   header->length));
-                       return (status);
-               }
-
-               /* Save allocation type */
-
-               allocation = ACPI_MEM_MAPPED;
-               break;
-
-       default:
-
-               ACPI_ERROR((AE_INFO, "Invalid address flags %X",
-                           address->pointer_type));
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
-       /*
-        * Validate checksum for _most_ tables,
-        * even the ones whose signature we don't recognize
-        */
-       if (table_info->type != ACPI_TABLE_ID_FACS) {
-               status = acpi_tb_verify_table_checksum(full_table);
-
-#if (!ACPI_CHECKSUM_ABORT)
-               if (ACPI_FAILURE(status)) {
-
-                       /* Ignore the error if configuration says so */
-
-                       status = AE_OK;
-               }
-#endif
-       }
-
-       /* Return values */
-
-       table_info->pointer = full_table;
-       table_info->length = (acpi_size) header->length;
-       table_info->allocation = allocation;
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                         "Found table [%4.4s] at %8.8X%8.8X, mapped/copied to %p\n",
-                         full_table->signature,
-                         ACPI_FORMAT_UINT64(address->pointer.physical),
-                         full_table));
-
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_table_ptr
- *
- * PARAMETERS:  table_type      - one of the defined table types
- *              Instance        - Which table of this type
- *              return_table    - pointer to location to place the pointer for
- *                                return
- *
- * RETURN:      Status
- *
- * DESCRIPTION: This function is called to get the pointer to an ACPI table.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_get_table_ptr(acpi_table_type table_type,
-                     u32 instance, struct acpi_table_header **return_table)
-{
-       struct acpi_table_desc *table_desc;
-       u32 i;
-
-       ACPI_FUNCTION_TRACE(tb_get_table_ptr);
-
-       if (table_type > ACPI_TABLE_ID_MAX) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
-       /* Check for instance out of range of the current table count */
-
-       if (instance > acpi_gbl_table_lists[table_type].count) {
-               return_ACPI_STATUS(AE_NOT_EXIST);
-       }
-
-       /*
-        * Walk the list to get the desired table
-        * Note: Instance is one-based
-        */
-       table_desc = acpi_gbl_table_lists[table_type].next;
-       for (i = 1; i < instance; i++) {
-               table_desc = table_desc->next;
-       }
-
-       /* We are now pointing to the requested table's descriptor */
-
-       *return_table = table_desc->pointer;
-       return_ACPI_STATUS(AE_OK);
-}
diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c
deleted file mode 100644 (file)
index ad98211..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbgetall - Get all required ACPI tables
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * 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,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any 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.
- *
- * NO WARRANTY
- * 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 MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT          ACPI_TABLES
-ACPI_MODULE_NAME("tbgetall")
-
-/* Local prototypes */
-static acpi_status
-acpi_tb_get_primary_table(struct acpi_pointer *address,
-                         struct acpi_table_desc *table_info);
-
-static acpi_status
-acpi_tb_get_secondary_table(struct acpi_pointer *address,
-                           acpi_string signature,
-                           struct acpi_table_desc *table_info);
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_primary_table
- *
- * PARAMETERS:  Address             - Physical address of table to retrieve
- *              *table_info         - Where the table info is returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Maps the physical address of table into a logical address
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_primary_table(struct acpi_pointer *address,
-                         struct acpi_table_desc *table_info)
-{
-       acpi_status status;
-       struct acpi_table_header header;
-
-       ACPI_FUNCTION_TRACE(tb_get_primary_table);
-
-       /* Ignore a NULL address in the RSDT */
-
-       if (!address->pointer.value) {
-               return_ACPI_STATUS(AE_OK);
-       }
-
-       /* Get the header in order to get signature and table size */
-
-       status = acpi_tb_get_table_header(address, &header);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /* Clear the table_info */
-
-       ACPI_MEMSET(table_info, 0, sizeof(struct acpi_table_desc));
-
-       /*
-        * Check the table signature and make sure it is recognized.
-        * Also checks the header checksum
-        */
-       table_info->pointer = &header;
-       status = acpi_tb_recognize_table(table_info, ACPI_TABLE_PRIMARY);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /* Get the entire table */
-
-       status = acpi_tb_get_table_body(address, &header, table_info);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /* Install the table */
-
-       status = acpi_tb_install_table(table_info);
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_secondary_table
- *
- * PARAMETERS:  Address             - Physical address of table to retrieve
- *              *table_info         - Where the table info is returned
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Maps the physical address of table into a logical address
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_get_secondary_table(struct acpi_pointer *address,
-                           acpi_string signature,
-                           struct acpi_table_desc *table_info)
-{
-       acpi_status status;
-       struct acpi_table_header header;
-
-       ACPI_FUNCTION_TRACE_STR(tb_get_secondary_table, signature);
-
-       /* Get the header in order to match the signature */
-
-       status = acpi_tb_get_table_header(address, &header);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /* Signature must match request */
-
-       if (!ACPI_COMPARE_NAME(header.signature, signature)) {
-               ACPI_ERROR((AE_INFO,
-                           "Incorrect table signature - wanted [%s] found [%4.4s]",
-                           signature, header.signature));
-               return_ACPI_STATUS(AE_BAD_SIGNATURE);
-       }
-
-       /*
-        * Check the table signature and make sure it is recognized.
-        * Also checks the header checksum
-        */
-       table_info->pointer = &header;
-       status = acpi_tb_recognize_table(table_info, ACPI_TABLE_SECONDARY);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /* Get the entire table */
-
-       status = acpi_tb_get_table_body(address, &header, table_info);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /* Install the table */
-
-       status = acpi_tb_install_table(table_info);
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_required_tables
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Load and validate tables other than the RSDT.  The RSDT must
- *              already be loaded and validated.
- *
- *              Get the minimum set of ACPI tables, namely:
- *
- *              1) FADT (via RSDT in loop below)
- *              2) FACS (via FADT)
- *              3) DSDT (via FADT)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_get_required_tables(void)
-{
-       acpi_status status = AE_OK;
-       u32 i;
-       struct acpi_table_desc table_info;
-       struct acpi_pointer address;
-
-       ACPI_FUNCTION_TRACE(tb_get_required_tables);
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%d ACPI tables in RSDT\n",
-                         acpi_gbl_rsdt_table_count));
-
-       address.pointer_type = acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
-
-       /*
-        * Loop through all table pointers found in RSDT.
-        * This will NOT include the FACS and DSDT - we must get
-        * them after the loop.
-        *
-        * The only tables we are interested in getting here is the FADT and
-        * any SSDTs.
-        */
-       for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
-
-               /* Get the table address from the common internal XSDT */
-
-               address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i];
-
-               /*
-                * Get the tables needed by this subsystem (FADT and any SSDTs).
-                * NOTE: All other tables are completely ignored at this time.
-                */
-               status = acpi_tb_get_primary_table(&address, &table_info);
-               if ((status != AE_OK) && (status != AE_TABLE_NOT_SUPPORTED)) {
-                       ACPI_WARNING((AE_INFO,
-                                     "%s, while getting table at %8.8X%8.8X",
-                                     acpi_format_exception(status),
-                                     ACPI_FORMAT_UINT64(address.pointer.
-                                                        value)));
-               }
-       }
-
-       /* We must have a FADT to continue */
-
-       if (!acpi_gbl_FADT) {
-               ACPI_ERROR((AE_INFO, "No FADT present in RSDT/XSDT"));
-               return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-       }
-
-       /*
-        * Convert the FADT to a common format.  This allows earlier revisions of
-        * the table to coexist with newer versions, using common access code.
-        */
-       status = acpi_tb_convert_table_fadt();
-       if (ACPI_FAILURE(status)) {
-               ACPI_ERROR((AE_INFO,
-                           "Could not convert FADT to internal common format"));
-               return_ACPI_STATUS(status);
-       }
-
-       /* Get the FACS (Pointed to by the FADT) */
-
-       address.pointer.value = acpi_gbl_FADT->xfirmware_ctrl;
-
-       status = acpi_tb_get_secondary_table(&address, FACS_SIG, &table_info);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Could not get/install the FACS"));
-               return_ACPI_STATUS(status);
-       }
-
-       /*
-        * Create the common FACS pointer table
-        * (Contains pointers to the original table)
-        */
-       status = acpi_tb_build_common_facs(&table_info);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /* Get/install the DSDT (Pointed to by the FADT) */
-
-       address.pointer.value = acpi_gbl_FADT->Xdsdt;
-
-       status = acpi_tb_get_secondary_table(&address, DSDT_SIG, &table_info);
-       if (ACPI_FAILURE(status)) {
-               ACPI_ERROR((AE_INFO, "Could not get/install the DSDT"));
-               return_ACPI_STATUS(status);
-       }
-
-       /* Set Integer Width (32/64) based upon DSDT revision */
-
-       acpi_ut_set_integer_width(acpi_gbl_DSDT->revision);
-
-       /* Dump the entire DSDT */
-
-       ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
-                         "Hex dump of entire DSDT, size %d (0x%X), Integer width = %d\n",
-                         acpi_gbl_DSDT->length, acpi_gbl_DSDT->length,
-                         acpi_gbl_integer_bit_width));
-
-       ACPI_DUMP_BUFFER(ACPI_CAST_PTR(u8, acpi_gbl_DSDT),
-                        acpi_gbl_DSDT->length);
-
-       /* Always delete the RSDP mapping, we are done with it */
-
-       acpi_tb_delete_tables_by_type(ACPI_TABLE_ID_RSDP);
-       return_ACPI_STATUS(status);
-}
index 1668a23..0e7b121 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  */
 
 #include <acpi/acpi.h>
+#include <acpi/acnamesp.h>
 #include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_TABLES
 ACPI_MODULE_NAME("tbinstal")
 
-/* Local prototypes */
-static acpi_status
-acpi_tb_match_signature(char *signature,
-                       struct acpi_table_desc *table_info, u8 search_type);
-
-/*******************************************************************************
+/******************************************************************************
  *
- * FUNCTION:    acpi_tb_match_signature
+ * FUNCTION:    acpi_tb_verify_table
  *
- * PARAMETERS:  Signature           - Table signature to match
- *              table_info          - Return data
- *              search_type         - Table type to match (primary/secondary)
+ * PARAMETERS:  table_desc          - table
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Compare signature against the list of "ACPI-subsystem-owned"
- *              tables (DSDT/FADT/SSDT, etc.) Returns the table_type_iD on match.
+ * DESCRIPTION: this function is called to verify and map table
  *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_match_signature(char *signature,
-                       struct acpi_table_desc *table_info, u8 search_type)
+ *****************************************************************************/
+acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc)
 {
-       acpi_native_uint i;
+       acpi_status status = AE_OK;
 
-       ACPI_FUNCTION_TRACE(tb_match_signature);
+       ACPI_FUNCTION_TRACE(tb_verify_table);
 
-       /* Search for a signature match among the known table types */
+       /* Map the table if necessary */
 
-       for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
-               if (!(acpi_gbl_table_data[i].flags & search_type)) {
-                       continue;
+       if (!table_desc->pointer) {
+               if ((table_desc->flags & ACPI_TABLE_ORIGIN_MASK) ==
+                   ACPI_TABLE_ORIGIN_MAPPED) {
+                       table_desc->pointer =
+                           acpi_os_map_memory(table_desc->address,
+                                              table_desc->length);
                }
+               if (!table_desc->pointer) {
+                       return_ACPI_STATUS(AE_NO_MEMORY);
+               }
+       }
 
-               if (!ACPI_STRNCMP(signature, acpi_gbl_table_data[i].signature,
-                                 acpi_gbl_table_data[i].sig_length)) {
-
-                       /* Found a signature match, return index if requested */
+       /* FACS is the odd table, has no standard ACPI header and no checksum */
 
-                       if (table_info) {
-                               table_info->type = (u8) i;
-                       }
+       if (!ACPI_COMPARE_NAME(&table_desc->signature, ACPI_SIG_FACS)) {
 
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                                         "Table [%4.4s] is an ACPI table consumed by the core subsystem\n",
-                                         (char *)acpi_gbl_table_data[i].
-                                         signature));
+               /* Always calculate checksum, ignore bad checksum if requested */
 
-                       return_ACPI_STATUS(AE_OK);
-               }
+               status =
+                   acpi_tb_verify_checksum(table_desc->pointer,
+                                           table_desc->length);
        }
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                         "Table [%4.4s] is not an ACPI table consumed by the core subsystem - ignored\n",
-                         (char *)signature));
-
-       return_ACPI_STATUS(AE_TABLE_NOT_SUPPORTED);
+       return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_install_table
+ * FUNCTION:    acpi_tb_add_table
  *
- * PARAMETERS:  table_info          - Return value from acpi_tb_get_table_body
+ * PARAMETERS:  table_desc          - Table descriptor
+ *              table_index         - Where the table index is returned
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Install the table into the global data structures.
+ * DESCRIPTION: This function is called to add the ACPI table
  *
  ******************************************************************************/
 
-acpi_status acpi_tb_install_table(struct acpi_table_desc *table_info)
+acpi_status
+acpi_tb_add_table(struct acpi_table_desc *table_desc,
+                 acpi_native_uint * table_index)
 {
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE(tb_install_table);
+       acpi_native_uint i;
+       acpi_native_uint length;
+       acpi_status status = AE_OK;
 
-       /* Lock tables while installing */
+       ACPI_FUNCTION_TRACE(tb_add_table);
 
-       status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Could not acquire table mutex"));
-               return_ACPI_STATUS(status);
+       if (!table_desc->pointer) {
+               status = acpi_tb_verify_table(table_desc);
+               if (ACPI_FAILURE(status) || !table_desc->pointer) {
+                       return_ACPI_STATUS(status);
+               }
        }
 
-       /*
-        * Ignore a table that is already installed. For example, some BIOS
-        * ASL code will repeatedly attempt to load the same SSDT.
-        */
-       status = acpi_tb_is_table_installed(table_info);
-       if (ACPI_FAILURE(status)) {
-               goto unlock_and_exit;
+       /* The table must be either an SSDT or a PSDT */
+
+       if ((!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_PSDT))
+           &&
+           (!ACPI_COMPARE_NAME(table_desc->pointer->signature, ACPI_SIG_SSDT)))
+       {
+               ACPI_ERROR((AE_INFO,
+                           "Table has invalid signature [%4.4s], must be SSDT or PSDT",
+                           table_desc->pointer->signature));
+               return_ACPI_STATUS(AE_BAD_SIGNATURE);
        }
 
-       /* Install the table into the global data structure */
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+       /* Check if table is already registered */
+
+       for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+               if (!acpi_gbl_root_table_list.tables[i].pointer) {
+                       status =
+                           acpi_tb_verify_table(&acpi_gbl_root_table_list.
+                                                tables[i]);
+                       if (ACPI_FAILURE(status)
+                           || !acpi_gbl_root_table_list.tables[i].pointer) {
+                               continue;
+                       }
+               }
+
+               length = ACPI_MIN(table_desc->length,
+                                 acpi_gbl_root_table_list.tables[i].length);
+               if (ACPI_MEMCMP(table_desc->pointer,
+                               acpi_gbl_root_table_list.tables[i].pointer,
+                               length)) {
+                       continue;
+               }
+
+               /* Table is already registered */
+
+               acpi_tb_delete_table(table_desc);
+               *table_index = i;
+               goto release;
+       }
 
-       status = acpi_tb_init_table_descriptor(table_info->type, table_info);
+       /*
+        * Add the table to the global table list
+        */
+       status = acpi_tb_store_table(table_desc->address, table_desc->pointer,
+                                    table_desc->length, table_desc->flags,
+                                    table_index);
        if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Could not install table [%4.4s]",
-                               table_info->pointer->signature));
+               goto release;
        }
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "%s located at %p\n",
-                         acpi_gbl_table_data[table_info->type].name,
-                         table_info->pointer));
+       acpi_tb_print_table_header(table_desc->address, table_desc->pointer);
 
-      unlock_and_exit:
+      release:
        (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
        return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_recognize_table
+ * FUNCTION:    acpi_tb_resize_root_table_list
  *
- * PARAMETERS:  table_info          - Return value from acpi_tb_get_table_body
- *              search_type         - Table type to match (primary/secondary)
+ * PARAMETERS:  None
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Check a table signature for a match against known table types
- *
- * NOTE:  All table pointers are validated as follows:
- *          1) Table pointer must point to valid physical memory
- *          2) Signature must be 4 ASCII chars, even if we don't recognize the
- *             name
- *          3) Table must be readable for length specified in the header
- *          4) Table checksum must be valid (with the exception of the FACS
- *             which has no checksum for some odd reason)
+ * DESCRIPTION: Expand the size of global table array
  *
  ******************************************************************************/
 
-acpi_status
-acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type)
+acpi_status acpi_tb_resize_root_table_list(void)
 {
-       struct acpi_table_header *table_header;
-       acpi_status status;
+       struct acpi_table_desc *tables;
 
-       ACPI_FUNCTION_TRACE(tb_recognize_table);
+       ACPI_FUNCTION_TRACE(tb_resize_root_table_list);
 
-       /* Ensure that we have a valid table pointer */
+       /* allow_resize flag is a parameter to acpi_initialize_tables */
 
-       table_header = (struct acpi_table_header *)table_info->pointer;
-       if (!table_header) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
+       if (!(acpi_gbl_root_table_list.flags & ACPI_ROOT_ALLOW_RESIZE)) {
+               ACPI_ERROR((AE_INFO,
+                           "Resize of Root Table Array is not allowed"));
+               return_ACPI_STATUS(AE_SUPPORT);
        }
 
-       /*
-        * We only "recognize" a limited number of ACPI tables -- namely, the
-        * ones that are used by the subsystem (DSDT, FADT, etc.)
-        *
-        * An AE_TABLE_NOT_SUPPORTED means that the table was not recognized.
-        * This can be any one of many valid ACPI tables, it just isn't one of
-        * the tables that is consumed by the core subsystem
-        */
-       status = acpi_tb_match_signature(table_header->signature,
-                                        table_info, search_type);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
+       /* Increase the Table Array size */
+
+       tables = ACPI_ALLOCATE_ZEROED((acpi_gbl_root_table_list.size +
+                                      ACPI_ROOT_TABLE_SIZE_INCREMENT)
+                                     * sizeof(struct acpi_table_desc));
+       if (!tables) {
+               ACPI_ERROR((AE_INFO,
+                           "Could not allocate new root table array"));
+               return_ACPI_STATUS(AE_NO_MEMORY);
        }
 
-       status = acpi_tb_validate_table_header(table_header);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
+       /* Copy and free the previous table array */
+
+       if (acpi_gbl_root_table_list.tables) {
+               ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables,
+                           acpi_gbl_root_table_list.size *
+                           sizeof(struct acpi_table_desc));
+
+               if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+                       ACPI_FREE(acpi_gbl_root_table_list.tables);
+               }
        }
 
-       /* Return the table type and length via the info struct */
+       acpi_gbl_root_table_list.tables = tables;
+       acpi_gbl_root_table_list.size += ACPI_ROOT_TABLE_SIZE_INCREMENT;
+       acpi_gbl_root_table_list.flags |= (u8) ACPI_ROOT_ORIGIN_ALLOCATED;
 
-       table_info->length = (acpi_size) table_header->length;
-       return_ACPI_STATUS(status);
+       return_ACPI_STATUS(AE_OK);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_init_table_descriptor
+ * FUNCTION:    acpi_tb_store_table
  *
- * PARAMETERS:  table_type          - The type of the table
- *              table_info          - A table info struct
+ * PARAMETERS:  Address             - Table address
+ *              Table               - Table header
+ *              Length              - Table length
+ *              Flags               - flags
  *
- * RETURN:      None.
+ * RETURN:      Status and table index.
  *
- * DESCRIPTION: Install a table into the global data structs.
+ * DESCRIPTION: Add an ACPI table to the global table list
  *
  ******************************************************************************/
 
 acpi_status
-acpi_tb_init_table_descriptor(acpi_table_type table_type,
-                             struct acpi_table_desc *table_info)
+acpi_tb_store_table(acpi_physical_address address,
+                   struct acpi_table_header *table,
+                   u32 length, u8 flags, acpi_native_uint * table_index)
 {
-       struct acpi_table_list *list_head;
-       struct acpi_table_desc *table_desc;
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE_U32(tb_init_table_descriptor, table_type);
+       acpi_status status = AE_OK;
 
-       /* Allocate a descriptor for this table */
+       /* Ensure that there is room for the table in the Root Table List */
 
-       table_desc = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc));
-       if (!table_desc) {
-               return_ACPI_STATUS(AE_NO_MEMORY);
+       if (acpi_gbl_root_table_list.count >= acpi_gbl_root_table_list.size) {
+               status = acpi_tb_resize_root_table_list();
+               if (ACPI_FAILURE(status)) {
+                       return (status);
+               }
        }
 
-       /* Get a new owner ID for the table */
+       /* Initialize added table */
+
+       acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+           address = address;
+       acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+           pointer = table;
+       acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].length =
+           length;
+       acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+           owner_id = 0;
+       acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].flags =
+           flags;
+
+       ACPI_MOVE_32_TO_32(&
+                          (acpi_gbl_root_table_list.
+                           tables[acpi_gbl_root_table_list.count].signature),
+                          table->signature);
+
+       *table_index = acpi_gbl_root_table_list.count;
+       acpi_gbl_root_table_list.count++;
+       return (status);
+}
 
-       status = acpi_ut_allocate_owner_id(&table_desc->owner_id);
-       if (ACPI_FAILURE(status)) {
-               goto error_exit1;
-       }
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_delete_table
+ *
+ * PARAMETERS:  table_index         - Table index
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Delete one internal ACPI table
+ *
+ ******************************************************************************/
 
-       /* Install the table into the global data structure */
+void acpi_tb_delete_table(struct acpi_table_desc *table_desc)
+{
+       /* Table must be mapped or allocated */
+       if (!table_desc->pointer) {
+               return;
+       }
+       switch (table_desc->flags & ACPI_TABLE_ORIGIN_MASK) {
+       case ACPI_TABLE_ORIGIN_MAPPED:
+               acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
+               break;
+       case ACPI_TABLE_ORIGIN_ALLOCATED:
+               ACPI_FREE(table_desc->pointer);
+               break;
+       default:;
+       }
 
-       list_head = &acpi_gbl_table_lists[table_type];
+       table_desc->pointer = NULL;
+}
 
-       /*
-        * Two major types of tables:  1) Only one instance is allowed.  This
-        * includes most ACPI tables such as the DSDT.  2) Multiple instances of
-        * the table are allowed.  This includes SSDT and PSDTs.
-        */
-       if (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags)) {
-               /*
-                * Only one table allowed, and a table has alread been installed
-                * at this location, so return an error.
-                */
-               if (list_head->next) {
-                       status = AE_ALREADY_EXISTS;
-                       goto error_exit2;
-               }
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_terminate
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Delete all internal ACPI tables
+ *
+ ******************************************************************************/
 
-               table_desc->next = list_head->next;
-               list_head->next = table_desc;
+void acpi_tb_terminate(void)
+{
+       acpi_native_uint i;
 
-               if (table_desc->next) {
-                       table_desc->next->prev = table_desc;
-               }
+       ACPI_FUNCTION_TRACE(tb_terminate);
 
-               list_head->count++;
-       } else {
-               /*
-                * Link the new table in to the list of tables of this type.
-                * Insert at the end of the list, order IS IMPORTANT.
-                *
-                * table_desc->Prev & Next are already NULL from calloc()
-                */
-               list_head->count++;
-
-               if (!list_head->next) {
-                       list_head->next = table_desc;
-               } else {
-                       table_desc->next = list_head->next;
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
 
-                       while (table_desc->next->next) {
-                               table_desc->next = table_desc->next->next;
-                       }
+       /* Delete the individual tables */
 
-                       table_desc->next->next = table_desc;
-                       table_desc->prev = table_desc->next;
-                       table_desc->next = NULL;
-               }
+       for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+               acpi_tb_delete_table(&acpi_gbl_root_table_list.tables[i]);
        }
 
-       /* Finish initialization of the table descriptor */
-
-       table_desc->loaded_into_namespace = FALSE;
-       table_desc->type = (u8) table_type;
-       table_desc->pointer = table_info->pointer;
-       table_desc->length = table_info->length;
-       table_desc->allocation = table_info->allocation;
-       table_desc->aml_start = (u8 *) (table_desc->pointer + 1),
-           table_desc->aml_length = (u32)
-           (table_desc->length - (u32) sizeof(struct acpi_table_header));
-
        /*
-        * Set the appropriate global pointer (if there is one) to point to the
-        * newly installed table
+        * Delete the root table array if allocated locally. Array cannot be
+        * mapped, so we don't need to check for that flag.
         */
-       if (acpi_gbl_table_data[table_type].global_ptr) {
-               *(acpi_gbl_table_data[table_type].global_ptr) =
-                   table_info->pointer;
+       if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+               ACPI_FREE(acpi_gbl_root_table_list.tables);
        }
 
-       /* Return Data */
-
-       table_info->owner_id = table_desc->owner_id;
-       table_info->installed_desc = table_desc;
-       return_ACPI_STATUS(AE_OK);
-
-       /* Error exit with cleanup */
-
-      error_exit2:
-
-       acpi_ut_release_owner_id(&table_desc->owner_id);
+       acpi_gbl_root_table_list.tables = NULL;
+       acpi_gbl_root_table_list.flags = 0;
+       acpi_gbl_root_table_list.count = 0;
 
-      error_exit1:
-
-       ACPI_FREE(table_desc);
-       return_ACPI_STATUS(status);
+       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "ACPI Tables freed\n"));
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_delete_all_tables
+ * FUNCTION:    acpi_tb_delete_namespace_by_owner
  *
- * PARAMETERS:  None.
+ * PARAMETERS:  table_index         - Table index
  *
- * RETURN:      None.
+ * RETURN:      None
  *
- * DESCRIPTION: Delete all internal ACPI tables
+ * DESCRIPTION: Delete all namespace objects created when this table was loaded.
  *
  ******************************************************************************/
 
-void acpi_tb_delete_all_tables(void)
+void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index)
 {
-       acpi_table_type type;
+       acpi_owner_id owner_id;
 
-       /*
-        * Free memory allocated for ACPI tables
-        * Memory can either be mapped or allocated
-        */
-       for (type = 0; type < (ACPI_TABLE_ID_MAX + 1); type++) {
-               acpi_tb_delete_tables_by_type(type);
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       if (table_index < acpi_gbl_root_table_list.count) {
+               owner_id =
+                   acpi_gbl_root_table_list.tables[table_index].owner_id;
+       } else {
+               (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+               return;
        }
+
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       acpi_ns_delete_namespace_by_owner(owner_id);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_delete_tables_by_type
+ * FUNCTION:    acpi_tb_allocate_owner_id
  *
- * PARAMETERS:  Type                - The table type to be deleted
+ * PARAMETERS:  table_index         - Table index
  *
- * RETURN:      None.
+ * RETURN:      Status
  *
- * DESCRIPTION: Delete an internal ACPI table
- *              Locks the ACPI table mutex
+ * DESCRIPTION: Allocates owner_id in table_desc
  *
  ******************************************************************************/
 
-void acpi_tb_delete_tables_by_type(acpi_table_type type)
+acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index)
 {
-       struct acpi_table_desc *table_desc;
-       u32 count;
-       u32 i;
+       acpi_status status = AE_BAD_PARAMETER;
 
-       ACPI_FUNCTION_TRACE_U32(tb_delete_tables_by_type, type);
+       ACPI_FUNCTION_TRACE(tb_allocate_owner_id);
 
-       if (type > ACPI_TABLE_ID_MAX) {
-               return_VOID;
-       }
-
-       if (ACPI_FAILURE(acpi_ut_acquire_mutex(ACPI_MTX_TABLES))) {
-               return;
-       }
-
-       /* Clear the appropriate "typed" global table pointer */
-
-       switch (type) {
-       case ACPI_TABLE_ID_RSDP:
-               acpi_gbl_RSDP = NULL;
-               break;
-
-       case ACPI_TABLE_ID_DSDT:
-               acpi_gbl_DSDT = NULL;
-               break;
-
-       case ACPI_TABLE_ID_FADT:
-               acpi_gbl_FADT = NULL;
-               break;
-
-       case ACPI_TABLE_ID_FACS:
-               acpi_gbl_FACS = NULL;
-               break;
-
-       case ACPI_TABLE_ID_XSDT:
-               acpi_gbl_XSDT = NULL;
-               break;
-
-       case ACPI_TABLE_ID_SSDT:
-       case ACPI_TABLE_ID_PSDT:
-       default:
-               break;
-       }
-
-       /*
-        * Free the table
-        * 1) Get the head of the list
-        */
-       table_desc = acpi_gbl_table_lists[type].next;
-       count = acpi_gbl_table_lists[type].count;
-
-       /*
-        * 2) Walk the entire list, deleting both the allocated tables
-        *    and the table descriptors
-        */
-       for (i = 0; i < count; i++) {
-               table_desc = acpi_tb_uninstall_table(table_desc);
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       if (table_index < acpi_gbl_root_table_list.count) {
+               status = acpi_ut_allocate_owner_id
+                   (&(acpi_gbl_root_table_list.tables[table_index].owner_id));
        }
 
        (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-       return_VOID;
+       return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_delete_single_table
+ * FUNCTION:    acpi_tb_release_owner_id
  *
- * PARAMETERS:  table_info          - A table info struct
+ * PARAMETERS:  table_index         - Table index
  *
- * RETURN:      None.
+ * RETURN:      Status
  *
- * DESCRIPTION: Low-level free for a single ACPI table.  Handles cases where
- *              the table was allocated a buffer or was mapped.
+ * DESCRIPTION: Releases owner_id in table_desc
  *
  ******************************************************************************/
 
-void acpi_tb_delete_single_table(struct acpi_table_desc *table_desc)
+acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index)
 {
+       acpi_status status = AE_BAD_PARAMETER;
 
-       /* Must have a valid table descriptor and pointer */
+       ACPI_FUNCTION_TRACE(tb_release_owner_id);
 
-       if ((!table_desc) || (!table_desc->pointer)) {
-               return;
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       if (table_index < acpi_gbl_root_table_list.count) {
+               acpi_ut_release_owner_id(&
+                                        (acpi_gbl_root_table_list.
+                                         tables[table_index].owner_id));
+               status = AE_OK;
        }
 
-       /* Valid table, determine type of memory allocation */
-
-       switch (table_desc->allocation) {
-       case ACPI_MEM_NOT_ALLOCATED:
-               break;
-
-       case ACPI_MEM_ALLOCATED:
-
-               ACPI_FREE(table_desc->pointer);
-               break;
-
-       case ACPI_MEM_MAPPED:
-
-               acpi_os_unmap_memory(table_desc->pointer, table_desc->length);
-               break;
-
-       default:
-               break;
-       }
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       return_ACPI_STATUS(status);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_uninstall_table
+ * FUNCTION:    acpi_tb_get_owner_id
  *
- * PARAMETERS:  table_info          - A table info struct
+ * PARAMETERS:  table_index         - Table index
+ *              owner_id            - Where the table owner_id is returned
  *
- * RETURN:      Pointer to the next table in the list (of same type)
+ * RETURN:      Status
  *
- * DESCRIPTION: Free the memory associated with an internal ACPI table that
- *              is either installed or has never been installed.
- *              Table mutex should be locked.
+ * DESCRIPTION: returns owner_id for the ACPI table
  *
  ******************************************************************************/
 
-struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc
-                                               *table_desc)
+acpi_status
+acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id)
 {
-       struct acpi_table_desc *next_desc;
+       acpi_status status = AE_BAD_PARAMETER;
 
-       ACPI_FUNCTION_TRACE_PTR(tb_uninstall_table, table_desc);
+       ACPI_FUNCTION_TRACE(tb_get_owner_id);
 
-       if (!table_desc) {
-               return_PTR(NULL);
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       if (table_index < acpi_gbl_root_table_list.count) {
+               *owner_id =
+                   acpi_gbl_root_table_list.tables[table_index].owner_id;
+               status = AE_OK;
        }
 
-       /* Unlink the descriptor from the doubly linked list */
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       return_ACPI_STATUS(status);
+}
 
-       if (table_desc->prev) {
-               table_desc->prev->next = table_desc->next;
-       } else {
-               /* Is first on list, update list head */
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_is_table_loaded
+ *
+ * PARAMETERS:  table_index         - Table index
+ *
+ * RETURN:      Table Loaded Flag
+ *
+ ******************************************************************************/
 
-               acpi_gbl_table_lists[table_desc->type].next = table_desc->next;
-       }
+u8 acpi_tb_is_table_loaded(acpi_native_uint table_index)
+{
+       u8 is_loaded = FALSE;
 
-       if (table_desc->next) {
-               table_desc->next->prev = table_desc->prev;
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       if (table_index < acpi_gbl_root_table_list.count) {
+               is_loaded = (u8)
+                   (acpi_gbl_root_table_list.tables[table_index].
+                    flags & ACPI_TABLE_IS_LOADED);
        }
 
-       /* Free the memory allocated for the table itself */
-
-       acpi_tb_delete_single_table(table_desc);
-
-       /* Free the owner ID associated with this table */
-
-       acpi_ut_release_owner_id(&table_desc->owner_id);
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       return (is_loaded);
+}
 
-       /* Free the table descriptor */
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_set_table_loaded_flag
+ *
+ * PARAMETERS:  table_index         - Table index
+ *              is_loaded           - TRUE if table is loaded, FALSE otherwise
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Sets the table loaded flag to either TRUE or FALSE.
+ *
+ ******************************************************************************/
 
-       next_desc = table_desc->next;
-       ACPI_FREE(table_desc);
+void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded)
+{
 
-       /* Return pointer to the next descriptor */
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       if (table_index < acpi_gbl_root_table_list.count) {
+               if (is_loaded) {
+                       acpi_gbl_root_table_list.tables[table_index].flags |=
+                           ACPI_TABLE_IS_LOADED;
+               } else {
+                       acpi_gbl_root_table_list.tables[table_index].flags &=
+                           ~ACPI_TABLE_IS_LOADED;
+               }
+       }
 
-       return_PTR(next_desc);
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
 }
diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
deleted file mode 100644 (file)
index 86a5fca..0000000
+++ /dev/null
@@ -1,307 +0,0 @@
-/******************************************************************************
- *
- * Module Name: tbrsdt - ACPI RSDT table utilities
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * 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,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any 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.
- *
- * NO WARRANTY
- * 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 MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#include <acpi/acpi.h>
-#include <acpi/actables.h>
-
-#define _COMPONENT          ACPI_TABLES
-ACPI_MODULE_NAME("tbrsdt")
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_verify_rsdp
- *
- * PARAMETERS:  Address         - RSDP (Pointer to RSDT)
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
- *
- ******************************************************************************/
-acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address)
-{
-       struct acpi_table_desc table_info;
-       acpi_status status;
-       struct rsdp_descriptor *rsdp;
-
-       ACPI_FUNCTION_TRACE(tb_verify_rsdp);
-
-       switch (address->pointer_type) {
-       case ACPI_LOGICAL_POINTER:
-
-               rsdp = address->pointer.logical;
-               break;
-
-       case ACPI_PHYSICAL_POINTER:
-               /*
-                * Obtain access to the RSDP structure
-                */
-               status = acpi_os_map_memory(address->pointer.physical,
-                                           sizeof(struct rsdp_descriptor),
-                                           ACPI_CAST_PTR(void, &rsdp));
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
-               }
-               break;
-
-       default:
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
-       /* Verify RSDP signature and checksum */
-
-       status = acpi_tb_validate_rsdp(rsdp);
-       if (ACPI_FAILURE(status)) {
-               goto cleanup;
-       }
-
-       /* RSDP is ok. Init the table info */
-
-       table_info.pointer = ACPI_CAST_PTR(struct acpi_table_header, rsdp);
-       table_info.length = sizeof(struct rsdp_descriptor);
-
-       if (address->pointer_type == ACPI_PHYSICAL_POINTER) {
-               table_info.allocation = ACPI_MEM_MAPPED;
-       } else {
-               table_info.allocation = ACPI_MEM_NOT_ALLOCATED;
-       }
-
-       /* Save the table pointers and allocation info */
-
-       status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_RSDP, &table_info);
-       if (ACPI_FAILURE(status)) {
-               goto cleanup;
-       }
-
-       /* Save the RSDP in a global for easy access */
-
-       acpi_gbl_RSDP =
-           ACPI_CAST_PTR(struct rsdp_descriptor, table_info.pointer);
-       return_ACPI_STATUS(status);
-
-       /* Error exit */
-      cleanup:
-
-       if (acpi_gbl_table_flags & ACPI_PHYSICAL_POINTER) {
-               acpi_os_unmap_memory(rsdp, sizeof(struct rsdp_descriptor));
-       }
-       return_ACPI_STATUS(status);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_rsdt_address
- *
- * PARAMETERS:  out_address         - Where the address is returned
- *
- * RETURN:      None, Address
- *
- * DESCRIPTION: Extract the address of either the RSDT or XSDT, depending on the
- *              version of the RSDP and whether the XSDT pointer is valid
- *
- ******************************************************************************/
-
-void acpi_tb_get_rsdt_address(struct acpi_pointer *out_address)
-{
-
-       ACPI_FUNCTION_ENTRY();
-
-       out_address->pointer_type =
-           acpi_gbl_table_flags | ACPI_LOGICAL_ADDRESSING;
-
-       /* Use XSDT if it is present */
-
-       if ((acpi_gbl_RSDP->revision >= 2) &&
-           acpi_gbl_RSDP->xsdt_physical_address) {
-               out_address->pointer.value =
-                   acpi_gbl_RSDP->xsdt_physical_address;
-               acpi_gbl_root_table_type = ACPI_TABLE_TYPE_XSDT;
-       } else {
-               /* No XSDT, use the RSDT */
-
-               out_address->pointer.value =
-                   acpi_gbl_RSDP->rsdt_physical_address;
-               acpi_gbl_root_table_type = ACPI_TABLE_TYPE_RSDT;
-       }
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_validate_rsdt
- *
- * PARAMETERS:  table_ptr       - Addressable pointer to the RSDT.
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Validate signature for the RSDT or XSDT
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr)
-{
-       char *signature;
-
-       ACPI_FUNCTION_ENTRY();
-
-       /* Validate minimum length */
-
-       if (table_ptr->length < sizeof(struct acpi_table_header)) {
-               ACPI_ERROR((AE_INFO,
-                           "RSDT/XSDT length (%X) is smaller than minimum (%zX)",
-                           table_ptr->length,
-                           sizeof(struct acpi_table_header)));
-
-               return (AE_INVALID_TABLE_LENGTH);
-       }
-
-       /* Search for appropriate signature, RSDT or XSDT */
-
-       if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
-               signature = RSDT_SIG;
-       } else {
-               signature = XSDT_SIG;
-       }
-
-       if (!ACPI_COMPARE_NAME(table_ptr->signature, signature)) {
-
-               /* Invalid RSDT or XSDT signature */
-
-               ACPI_ERROR((AE_INFO,
-                           "Invalid signature where RSDP indicates RSDT/XSDT should be located. RSDP:"));
-
-               ACPI_DUMP_BUFFER(acpi_gbl_RSDP, 20);
-
-               ACPI_ERROR((AE_INFO,
-                           "RSDT/XSDT signature at %X is invalid",
-                           acpi_gbl_RSDP->rsdt_physical_address));
-
-               if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
-                       ACPI_ERROR((AE_INFO, "Looking for RSDT"));
-               } else {
-                       ACPI_ERROR((AE_INFO, "Looking for XSDT"));
-               }
-
-               ACPI_DUMP_BUFFER(ACPI_CAST_PTR(char, table_ptr), 48);
-               return (AE_BAD_SIGNATURE);
-       }
-
-       return (AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_get_table_rsdt
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Load and validate the RSDP (ptr) and RSDT (table)
- *
- ******************************************************************************/
-
-acpi_status acpi_tb_get_table_rsdt(void)
-{
-       struct acpi_table_desc table_info;
-       acpi_status status;
-       struct acpi_pointer address;
-
-       ACPI_FUNCTION_TRACE(tb_get_table_rsdt);
-
-       /* Get the RSDT/XSDT via the RSDP */
-
-       acpi_tb_get_rsdt_address(&address);
-
-       table_info.type = ACPI_TABLE_ID_XSDT;
-       status = acpi_tb_get_table(&address, &table_info);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Could not get the RSDT/XSDT"));
-               return_ACPI_STATUS(status);
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                         "RSDP located at %p, points to RSDT physical=%8.8X%8.8X\n",
-                         acpi_gbl_RSDP,
-                         ACPI_FORMAT_UINT64(address.pointer.value)));
-
-       /* Check the RSDT or XSDT signature */
-
-       status = acpi_tb_validate_rsdt(table_info.pointer);
-       if (ACPI_FAILURE(status)) {
-               goto error_cleanup;
-       }
-
-       /* Get the number of tables defined in the RSDT or XSDT */
-
-       acpi_gbl_rsdt_table_count = acpi_tb_get_table_count(acpi_gbl_RSDP,
-                                                           table_info.pointer);
-
-       /* Convert and/or copy to an XSDT structure */
-
-       status = acpi_tb_convert_to_xsdt(&table_info);
-       if (ACPI_FAILURE(status)) {
-               goto error_cleanup;
-       }
-
-       /* Save the table pointers and allocation info */
-
-       status = acpi_tb_init_table_descriptor(ACPI_TABLE_ID_XSDT, &table_info);
-       if (ACPI_FAILURE(status)) {
-               goto error_cleanup;
-       }
-
-       acpi_gbl_XSDT =
-           ACPI_CAST_PTR(struct xsdt_descriptor, table_info.pointer);
-
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "XSDT located at %p\n", acpi_gbl_XSDT));
-       return_ACPI_STATUS(status);
-
-      error_cleanup:
-
-       /* Free table allocated by acpi_tb_get_table */
-
-       acpi_tb_delete_single_table(&table_info);
-
-       return_ACPI_STATUS(status);
-}
index 209a401..1da64b4 100644 (file)
@@ -1,11 +1,11 @@
 /******************************************************************************
  *
- * Module Name: tbutils - Table manipulation utilities
+ * Module Name: tbutils   - table utilities
  *
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 ACPI_MODULE_NAME("tbutils")
 
 /* Local prototypes */
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-acpi_status
-acpi_tb_handle_to_object(u16 table_id, struct acpi_table_desc **table_desc);
-#endif
+static acpi_physical_address
+acpi_tb_get_root_table_entry(u8 * table_entry,
+                            acpi_native_uint table_entry_size);
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_is_table_installed
- *
- * PARAMETERS:  new_table_desc      - Descriptor for new table being installed
+ * FUNCTION:    acpi_tb_tables_loaded
  *
- * RETURN:      Status - AE_ALREADY_EXISTS if the table is already installed
+ * PARAMETERS:  None
  *
- * DESCRIPTION: Determine if an ACPI table is already installed
+ * RETURN:      TRUE if required ACPI tables are loaded
  *
- * MUTEX:       Table data structures should be locked
+ * DESCRIPTION: Determine if the minimum required ACPI tables are present
+ *              (FADT, FACS, DSDT)
  *
  ******************************************************************************/
 
-acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc)
+u8 acpi_tb_tables_loaded(void)
 {
-       struct acpi_table_desc *table_desc;
-
-       ACPI_FUNCTION_TRACE(tb_is_table_installed);
 
-       /* Get the list descriptor and first table descriptor */
-
-       table_desc = acpi_gbl_table_lists[new_table_desc->type].next;
+       if (acpi_gbl_root_table_list.count >= 3) {
+               return (TRUE);
+       }
 
-       /* Examine all installed tables of this type */
+       return (FALSE);
+}
 
-       while (table_desc) {
-               /*
-                * If the table lengths match, perform a full bytewise compare. This
-                * means that we will allow tables with duplicate oem_table_id(s), as
-                * long as the tables are different in some way.
-                *
-                * Checking if the table has been loaded into the namespace means that
-                * we don't check for duplicate tables during the initial installation
-                * of tables within the RSDT/XSDT.
-                */
-               if ((table_desc->loaded_into_namespace) &&
-                   (table_desc->pointer->length ==
-                    new_table_desc->pointer->length)
-                   &&
-                   (!ACPI_MEMCMP
-                    (table_desc->pointer, new_table_desc->pointer,
-                     new_table_desc->pointer->length))) {
-
-                       /* Match: this table is already installed */
-
-                       ACPI_DEBUG_PRINT((ACPI_DB_TABLES,
-                                         "Table [%4.4s] already installed: Rev %X OemTableId [%8.8s]\n",
-                                         new_table_desc->pointer->signature,
-                                         new_table_desc->pointer->revision,
-                                         new_table_desc->pointer->
-                                         oem_table_id));
-
-                       new_table_desc->owner_id = table_desc->owner_id;
-                       new_table_desc->installed_desc = table_desc;
-
-                       return_ACPI_STATUS(AE_ALREADY_EXISTS);
-               }
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_tb_print_table_header
+ *
+ * PARAMETERS:  Address             - Table physical address
+ *              Header              - Table header
+ *
+ * RETURN:      None
+ *
+ * DESCRIPTION: Print an ACPI table header. Special cases for FACS and RSDP.
+ *
+ ******************************************************************************/
 
-               /* Get next table on the list */
+void
+acpi_tb_print_table_header(acpi_physical_address address,
+                          struct acpi_table_header *header)
+{
 
-               table_desc = table_desc->next;
+       if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_FACS)) {
+
+               /* FACS only has signature and length fields of common table header */
+
+               ACPI_INFO((AE_INFO, "%4.4s %08lX, %04X",
+                          header->signature, (unsigned long)address,
+                          header->length));
+       } else if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_RSDP)) {
+
+               /* RSDP has no common fields */
+
+               ACPI_INFO((AE_INFO, "RSDP %08lX, %04X (r%d %6.6s)",
+                          (unsigned long)address,
+                          (ACPI_CAST_PTR(struct acpi_table_rsdp, header)->
+                           revision >
+                           0) ? ACPI_CAST_PTR(struct acpi_table_rsdp,
+                                              header)->length : 20,
+                          ACPI_CAST_PTR(struct acpi_table_rsdp,
+                                        header)->revision,
+                          ACPI_CAST_PTR(struct acpi_table_rsdp,
+                                        header)->oem_id));
+       } else {
+               /* Standard ACPI table with full common header */
+
+               ACPI_INFO((AE_INFO,
+                          "%4.4s %08lX, %04X (r%d %6.6s %8.8s %8X %4.4s %8X)",
+                          header->signature, (unsigned long)address,
+                          header->length, header->revision, header->oem_id,
+                          header->oem_table_id, header->oem_revision,
+                          header->asl_compiler_id,
+                          header->asl_compiler_revision));
        }
-
-       return_ACPI_STATUS(AE_OK);
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_validate_table_header
+ * FUNCTION:    acpi_tb_validate_checksum
  *
- * PARAMETERS:  table_header        - Logical pointer to the table
+ * PARAMETERS:  Table               - ACPI table to verify
+ *              Length              - Length of entire table
  *
  * RETURN:      Status
  *
- * DESCRIPTION: Check an ACPI table header for validity
- *
- * NOTE:  Table pointers are validated as follows:
- *          1) Table pointer must point to valid physical memory
- *          2) Signature must be 4 ASCII chars, even if we don't recognize the
- *             name
- *          3) Table must be readable for length specified in the header
- *          4) Table checksum must be valid (with the exception of the FACS
- *              which has no checksum because it contains variable fields)
+ * DESCRIPTION: Verifies that the table checksums to zero. Optionally returns
+ *              exception on bad checksum.
  *
  ******************************************************************************/
 
-acpi_status
-acpi_tb_validate_table_header(struct acpi_table_header *table_header)
+acpi_status acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length)
 {
-       acpi_name signature;
-
-       ACPI_FUNCTION_ENTRY();
-
-       /* Verify that this is a valid address */
-
-       if (!acpi_os_readable(table_header, sizeof(struct acpi_table_header))) {
-               ACPI_ERROR((AE_INFO,
-                           "Cannot read table header at %p", table_header));
-
-               return (AE_BAD_ADDRESS);
-       }
+       u8 checksum;
 
-       /* Ensure that the signature is 4 ASCII characters */
+       /* Compute the checksum on the table */
 
-       ACPI_MOVE_32_TO_32(&signature, table_header->signature);
-       if (!acpi_ut_valid_acpi_name(signature)) {
-               ACPI_ERROR((AE_INFO, "Invalid table signature 0x%8.8X",
-                           signature));
+       checksum = acpi_tb_checksum(ACPI_CAST_PTR(u8, table), length);
 
-               ACPI_DUMP_BUFFER(table_header,
-                                sizeof(struct acpi_table_header));
-               return (AE_BAD_SIGNATURE);
-       }
+       /* Checksum ok? (should be zero) */
 
-       /* Validate the table length */
+       if (checksum) {
+               ACPI_WARNING((AE_INFO,
+                             "Incorrect checksum in table [%4.4s] -  %2.2X, should be %2.2X",
+                             table->signature, table->checksum,
+                             (u8) (table->checksum - checksum)));
 
-       if (table_header->length < sizeof(struct acpi_table_header)) {
-               ACPI_ERROR((AE_INFO,
-                           "Invalid length 0x%X in table with signature %4.4s",
-                           (u32) table_header->length,
-                           ACPI_CAST_PTR(char, &signature)));
+#if (ACPI_CHECKSUM_ABORT)
 
-               ACPI_DUMP_BUFFER(table_header,
-                                sizeof(struct acpi_table_header));
-               return (AE_BAD_HEADER);
+               return (AE_BAD_CHECKSUM);
+#endif
        }
 
        return (AE_OK);
@@ -186,157 +168,320 @@ acpi_tb_validate_table_header(struct acpi_table_header *table_header)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_sum_table
+ * FUNCTION:    acpi_tb_checksum
  *
- * PARAMETERS:  Buffer              - Buffer to sum
- *              Length              - Size of the buffer
+ * PARAMETERS:  Buffer          - Pointer to memory region to be checked
+ *              Length          - Length of this memory region
  *
- * RETURN:      8 bit sum of buffer
+ * RETURN:      Checksum (u8)
  *
- * DESCRIPTION: Computes an 8 bit sum of the buffer(length) and returns it.
+ * DESCRIPTION: Calculates circular checksum of memory region.
  *
  ******************************************************************************/
 
-u8 acpi_tb_sum_table(void *buffer, u32 length)
+u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length)
 {
-       acpi_native_uint i;
        u8 sum = 0;
+       u8 *end = buffer + length;
 
-       if (!buffer || !length) {
-               return (0);
+       while (buffer < end) {
+               sum = (u8) (sum + *(buffer++));
        }
 
-       for (i = 0; i < length; i++) {
-               sum = (u8) (sum + ((u8 *) buffer)[i]);
-       }
-       return (sum);
+       return sum;
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_generate_checksum
+ * FUNCTION:    acpi_tb_install_table
  *
- * PARAMETERS:  Table               - Pointer to a valid ACPI table (with a
- *                                    standard ACPI header)
+ * PARAMETERS:  Address                 - Physical address of DSDT or FACS
+ *              Flags                   - Flags
+ *              Signature               - Table signature, NULL if no need to
+ *                                        match
+ *              table_index             - Index into root table array
  *
- * RETURN:      8 bit checksum of buffer
+ * RETURN:      None
  *
- * DESCRIPTION: Computes an 8 bit checksum of the table.
+ * DESCRIPTION: Install an ACPI table into the global data structure.
  *
  ******************************************************************************/
 
-u8 acpi_tb_generate_checksum(struct acpi_table_header * table)
+void
+acpi_tb_install_table(acpi_physical_address address,
+                     u8 flags, char *signature, acpi_native_uint table_index)
 {
-       u8 checksum;
+       struct acpi_table_header *table;
+
+       if (!address) {
+               ACPI_ERROR((AE_INFO,
+                           "Null physical address for ACPI table [%s]",
+                           signature));
+               return;
+       }
+
+       /* Map just the table header */
+
+       table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+       if (!table) {
+               return;
+       }
+
+       /* If a particular signature is expected, signature must match */
+
+       if (signature && !ACPI_COMPARE_NAME(table->signature, signature)) {
+               ACPI_ERROR((AE_INFO,
+                           "Invalid signature 0x%X for ACPI table [%s]",
+                           *ACPI_CAST_PTR(u32, table->signature), signature));
+               goto unmap_and_exit;
+       }
 
-       /* Sum the entire table as-is */
+       /* Initialize the table entry */
 
-       checksum = acpi_tb_sum_table(table, table->length);
+       acpi_gbl_root_table_list.tables[table_index].address = address;
+       acpi_gbl_root_table_list.tables[table_index].length = table->length;
+       acpi_gbl_root_table_list.tables[table_index].flags = flags;
 
-       /* Subtract off the existing checksum value in the table */
+       ACPI_MOVE_32_TO_32(&
+                          (acpi_gbl_root_table_list.tables[table_index].
+                           signature), table->signature);
 
-       checksum = (u8) (checksum - table->checksum);
+       acpi_tb_print_table_header(address, table);
 
-       /* Compute the final checksum */
+       if (table_index == ACPI_TABLE_INDEX_DSDT) {
 
-       checksum = (u8) (0 - checksum);
-       return (checksum);
+               /* Global integer width is based upon revision of the DSDT */
+
+               acpi_ut_set_integer_width(table->revision);
+       }
+
+      unmap_and_exit:
+       acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_set_checksum
+ * FUNCTION:    acpi_tb_get_root_table_entry
  *
- * PARAMETERS:  Table               - Pointer to a valid ACPI table (with a
- *                                    standard ACPI header)
+ * PARAMETERS:  table_entry         - Pointer to the RSDT/XSDT table entry
+ *              table_entry_size    - sizeof 32 or 64 (RSDT or XSDT)
  *
- * RETURN:      None. Sets the table checksum field
+ * RETURN:      Physical address extracted from the root table
  *
- * DESCRIPTION: Computes an 8 bit checksum of the table and inserts the
- *              checksum into the table header.
+ * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on
+ *              both 32-bit and 64-bit platforms
+ *
+ * NOTE:        acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on
+ *              64-bit platforms.
  *
  ******************************************************************************/
 
-void acpi_tb_set_checksum(struct acpi_table_header *table)
+static acpi_physical_address
+acpi_tb_get_root_table_entry(u8 * table_entry,
+                            acpi_native_uint table_entry_size)
 {
+       u64 address64;
+
+       /*
+        * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
+        * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
+        */
+       if (table_entry_size == sizeof(u32)) {
+               /*
+                * 32-bit platform, RSDT: Return 32-bit table entry
+                * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
+                */
+               return ((acpi_physical_address)
+                       (*ACPI_CAST_PTR(u32, table_entry)));
+       } else {
+               /*
+                * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
+                * 64-bit platform, XSDT: Move (unaligned) 64-bit to local, return 64-bit
+                */
+               ACPI_MOVE_64_TO_64(&address64, table_entry);
 
-       table->checksum = acpi_tb_generate_checksum(table);
+#if ACPI_MACHINE_WIDTH == 32
+               if (address64 > ACPI_UINT32_MAX) {
+
+                       /* Will truncate 64-bit address to 32 bits, issue warning */
+
+                       ACPI_WARNING((AE_INFO,
+                                     "64-bit Physical Address in XSDT is too large (%8.8X%8.8X), truncating",
+                                     ACPI_FORMAT_UINT64(address64)));
+               }
+#endif
+               return ((acpi_physical_address) (address64));
+       }
 }
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_verify_table_checksum
+ * FUNCTION:    acpi_tb_parse_root_table
+ *
+ * PARAMETERS:  Rsdp                    - Pointer to the RSDP
+ *              Flags                   - Flags
  *
- * PARAMETERS:  *table_header           - ACPI table to verify
+ * RETURN:      Status
  *
- * RETURN:      8 bit checksum of table
+ * DESCRIPTION: This function is called to parse the Root System Description
+ *              Table (RSDT or XSDT)
  *
- * DESCRIPTION: Generates an 8 bit checksum of table and returns and compares
- *              it to the existing checksum value.
+ * NOTE:        Tables are mapped (not copied) for efficiency. The FACS must
+ *              be mapped and cannot be copied because it contains the actual
+ *              memory location of the ACPI Global Lock.
  *
  ******************************************************************************/
 
-acpi_status
-acpi_tb_verify_table_checksum(struct acpi_table_header *table_header)
+acpi_status __init
+acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags)
 {
-       u8 checksum;
+       struct acpi_table_rsdp *rsdp;
+       acpi_native_uint table_entry_size;
+       acpi_native_uint i;
+       u32 table_count;
+       struct acpi_table_header *table;
+       acpi_physical_address address;
+       u32 length;
+       u8 *table_entry;
+       acpi_status status;
+
+       ACPI_FUNCTION_TRACE(tb_parse_root_table);
+
+       /*
+        * Map the entire RSDP and extract the address of the RSDT or XSDT
+        */
+       rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
+       if (!rsdp) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
+       }
 
-       ACPI_FUNCTION_TRACE(tb_verify_table_checksum);
+       acpi_tb_print_table_header(rsdp_address,
+                                  ACPI_CAST_PTR(struct acpi_table_header,
+                                                rsdp));
 
-       /* Compute the checksum on the table */
+       /* Differentiate between RSDT and XSDT root tables */
 
-       checksum = acpi_tb_generate_checksum(table_header);
+       if (rsdp->revision > 1 && rsdp->xsdt_physical_address) {
+               /*
+                * Root table is an XSDT (64-bit physical addresses). We must use the
+                * XSDT if the revision is > 1 and the XSDT pointer is present, as per
+                * the ACPI specification.
+                */
+               address = (acpi_physical_address) rsdp->xsdt_physical_address;
+               table_entry_size = sizeof(u64);
+       } else {
+               /* Root table is an RSDT (32-bit physical addresses) */
 
-       /* Checksum ok? */
+               address = (acpi_physical_address) rsdp->rsdt_physical_address;
+               table_entry_size = sizeof(u32);
+       }
 
-       if (checksum == table_header->checksum) {
-               return_ACPI_STATUS(AE_OK);
+       /*
+        * It is not possible to map more than one entry in some environments,
+        * so unmap the RSDP here before mapping other tables
+        */
+       acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
+
+       /* Map the RSDT/XSDT table header to get the full table length */
+
+       table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
+       if (!table) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
        }
 
-       ACPI_WARNING((AE_INFO,
-                     "Incorrect checksum in table [%4.4s] - is %2.2X, should be %2.2X",
-                     table_header->signature, table_header->checksum,
-                     checksum));
+       acpi_tb_print_table_header(address, table);
 
-       return_ACPI_STATUS(AE_BAD_CHECKSUM);
-}
+       /* Get the length of the full table, verify length and map entire table */
 
-#ifdef ACPI_OBSOLETE_FUNCTIONS
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_handle_to_object
- *
- * PARAMETERS:  table_id            - Id for which the function is searching
- *              table_desc          - Pointer to return the matching table
- *                                      descriptor.
- *
- * RETURN:      Search the tables to find one with a matching table_id and
- *              return a pointer to that table descriptor.
- *
- ******************************************************************************/
+       length = table->length;
+       acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
 
-acpi_status
-acpi_tb_handle_to_object(u16 table_id,
-                        struct acpi_table_desc **return_table_desc)
-{
-       u32 i;
-       struct acpi_table_desc *table_desc;
+       if (length < sizeof(struct acpi_table_header)) {
+               ACPI_ERROR((AE_INFO, "Invalid length 0x%X in RSDT/XSDT",
+                           length));
+               return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
+       }
 
-       ACPI_FUNCTION_NAME(tb_handle_to_object);
+       table = acpi_os_map_memory(address, length);
+       if (!table) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
+       }
+
+       /* Validate the root table checksum */
+
+       status = acpi_tb_verify_checksum(table, length);
+       if (ACPI_FAILURE(status)) {
+               acpi_os_unmap_memory(table, length);
+               return_ACPI_STATUS(status);
+       }
 
-       for (i = 0; i < ACPI_TABLE_MAX; i++) {
-               table_desc = acpi_gbl_table_lists[i].next;
-               while (table_desc) {
-                       if (table_desc->table_id == table_id) {
-                               *return_table_desc = table_desc;
-                               return (AE_OK);
+       /* Calculate the number of tables described in the root table */
+
+       table_count =
+           (u32) ((table->length -
+                   sizeof(struct acpi_table_header)) / table_entry_size);
+
+       /*
+        * First two entries in the table array are reserved for the DSDT and FACS,
+        * which are not actually present in the RSDT/XSDT - they come from the FADT
+        */
+       table_entry =
+           ACPI_CAST_PTR(u8, table) + sizeof(struct acpi_table_header);
+       acpi_gbl_root_table_list.count = 2;
+
+       /*
+        * Initialize the root table array from the RSDT/XSDT
+        */
+       for (i = 0; i < table_count; i++) {
+               if (acpi_gbl_root_table_list.count >=
+                   acpi_gbl_root_table_list.size) {
+
+                       /* There is no more room in the root table array, attempt resize */
+
+                       status = acpi_tb_resize_root_table_list();
+                       if (ACPI_FAILURE(status)) {
+                               ACPI_WARNING((AE_INFO,
+                                             "Truncating %u table entries!",
+                                             (unsigned)
+                                             (acpi_gbl_root_table_list.size -
+                                              acpi_gbl_root_table_list.
+                                              count)));
+                               break;
                        }
+               }
+
+               /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
 
-                       table_desc = table_desc->next;
+               acpi_gbl_root_table_list.tables[acpi_gbl_root_table_list.count].
+                   address =
+                   acpi_tb_get_root_table_entry(table_entry, table_entry_size);
+
+               table_entry += table_entry_size;
+               acpi_gbl_root_table_list.count++;
+       }
+
+       /*
+        * It is not possible to map more than one entry in some environments,
+        * so unmap the root table here before mapping other tables
+        */
+       acpi_os_unmap_memory(table, length);
+
+       /*
+        * Complete the initialization of the root table array by examining
+        * the header of each table
+        */
+       for (i = 2; i < acpi_gbl_root_table_list.count; i++) {
+               acpi_tb_install_table(acpi_gbl_root_table_list.tables[i].
+                                     address, flags, NULL, i);
+
+               /* Special case for FADT - get the DSDT and FACS */
+
+               if (ACPI_COMPARE_NAME
+                   (&acpi_gbl_root_table_list.tables[i].signature,
+                    ACPI_SIG_FADT)) {
+                       acpi_tb_parse_fadt(i, flags);
                }
        }
 
-       ACPI_ERROR((AE_INFO, "TableId=%X does not exist", table_id));
-       return (AE_BAD_PARAMETER);
+       return_ACPI_STATUS(AE_OK);
 }
-#endif
index 5ba9303..807978d 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define _COMPONENT          ACPI_TABLES
 ACPI_MODULE_NAME("tbxface")
 
+/* Local prototypes */
+static acpi_status acpi_tb_load_namespace(void);
+
 /*******************************************************************************
  *
- * FUNCTION:    acpi_load_tables
+ * FUNCTION:    acpi_allocate_root_table
  *
- * PARAMETERS:  None
+ * PARAMETERS:  initial_table_count - Size of initial_table_array, in number of
+ *                                    struct acpi_table_desc structures
  *
  * RETURN:      Status
  *
- * DESCRIPTION: This function is called to load the ACPI tables from the
- *              provided RSDT
+ * DESCRIPTION: Allocate a root table array. Used by i_aSL compiler and
+ *              acpi_initialize_tables.
  *
  ******************************************************************************/
-acpi_status acpi_load_tables(void)
+
+acpi_status acpi_allocate_root_table(u32 initial_table_count)
 {
-       struct acpi_pointer rsdp_address;
-       acpi_status status;
 
-       ACPI_FUNCTION_TRACE(acpi_load_tables);
+       acpi_gbl_root_table_list.size = initial_table_count;
+       acpi_gbl_root_table_list.flags = ACPI_ROOT_ALLOW_RESIZE;
 
-       /* Get the RSDP */
+       return (acpi_tb_resize_root_table_list());
+}
 
-       status = acpi_os_get_root_pointer(ACPI_LOGICAL_ADDRESSING,
-                                         &rsdp_address);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status, "Could not get the RSDP"));
-               goto error_exit;
-       }
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_initialize_tables
+ *
+ * PARAMETERS:  initial_table_array - Pointer to an array of pre-allocated
+ *                                    struct acpi_table_desc structures. If NULL, the
+ *                                    array is dynamically allocated.
+ *              initial_table_count - Size of initial_table_array, in number of
+ *                                    struct acpi_table_desc structures
+ *              allow_realloc       - Flag to tell Table Manager if resize of
+ *                                    pre-allocated array is allowed. Ignored
+ *                                    if initial_table_array is NULL.
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Initialize the table manager, get the RSDP and RSDT/XSDT.
+ *
+ * NOTE:        Allows static allocation of the initial table array in order
+ *              to avoid the use of dynamic memory in confined environments
+ *              such as the kernel boot sequence where it may not be available.
+ *
+ *              If the host OS memory managers are initialized, use NULL for
+ *              initial_table_array, and the table will be dynamically allocated.
+ *
+ ******************************************************************************/
 
-       /* Map and validate the RSDP */
+acpi_status __init
+acpi_initialize_tables(struct acpi_table_desc * initial_table_array,
+                      u32 initial_table_count, u8 allow_resize)
+{
+       acpi_physical_address rsdp_address;
+       acpi_status status;
 
-       acpi_gbl_table_flags = rsdp_address.pointer_type;
+       ACPI_FUNCTION_TRACE(acpi_initialize_tables);
 
-       status = acpi_tb_verify_rsdp(&rsdp_address);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status, "During RSDP validation"));
-               goto error_exit;
+       /*
+        * Set up the Root Table Array
+        * Allocate the table array if requested
+        */
+       if (!initial_table_array) {
+               status = acpi_allocate_root_table(initial_table_count);
+               if (ACPI_FAILURE(status)) {
+                       return_ACPI_STATUS(status);
+               }
+       } else {
+               /* Root Table Array has been statically allocated by the host */
+
+               ACPI_MEMSET(initial_table_array, 0,
+                           initial_table_count *
+                           sizeof(struct acpi_table_desc));
+
+               acpi_gbl_root_table_list.tables = initial_table_array;
+               acpi_gbl_root_table_list.size = initial_table_count;
+               acpi_gbl_root_table_list.flags = ACPI_ROOT_ORIGIN_UNKNOWN;
+               if (allow_resize) {
+                       acpi_gbl_root_table_list.flags |=
+                           ACPI_ROOT_ALLOW_RESIZE;
+               }
        }
 
-       /* Get the RSDT via the RSDP */
+       /* Get the address of the RSDP */
 
-       status = acpi_tb_get_table_rsdt();
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status, "Could not load RSDT"));
-               goto error_exit;
+       rsdp_address = acpi_os_get_root_pointer();
+       if (!rsdp_address) {
+               return_ACPI_STATUS(AE_NOT_FOUND);
        }
 
-       /* Now get the tables needed by this subsystem (FADT, DSDT, etc.) */
+       /*
+        * Get the root table (RSDT or XSDT) and extract all entries to the local
+        * Root Table Array. This array contains the information of the RSDT/XSDT
+        * in a common, more useable format.
+        */
+       status =
+           acpi_tb_parse_root_table(rsdp_address, ACPI_TABLE_ORIGIN_MAPPED);
+       return_ACPI_STATUS(status);
+}
 
-       status = acpi_tb_get_required_tables();
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "Could not get all required tables (DSDT/FADT/FACS)"));
-               goto error_exit;
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_reallocate_root_table
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Reallocate Root Table List into dynamic memory. Copies the
+ *              root list from the previously provided scratch area. Should
+ *              be called once dynamic memory allocation is available in the
+ *              kernel
+ *
+ ******************************************************************************/
+acpi_status acpi_reallocate_root_table(void)
+{
+       struct acpi_table_desc *tables;
+       acpi_size new_size;
+
+       ACPI_FUNCTION_TRACE(acpi_reallocate_root_table);
+
+       /*
+        * Only reallocate the root table if the host provided a static buffer
+        * for the table array in the call to acpi_initialize_tables.
+        */
+       if (acpi_gbl_root_table_list.flags & ACPI_ROOT_ORIGIN_ALLOCATED) {
+               return_ACPI_STATUS(AE_SUPPORT);
        }
 
-       ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
+       new_size =
+           (acpi_gbl_root_table_list.count +
+            ACPI_ROOT_TABLE_SIZE_INCREMENT) * sizeof(struct acpi_table_desc);
 
-       /* Load the namespace from the tables */
+       /* Create new array and copy the old array */
 
-       status = acpi_ns_load_namespace();
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status, "Could not load namespace"));
-               goto error_exit;
+       tables = ACPI_ALLOCATE_ZEROED(new_size);
+       if (!tables) {
+               return_ACPI_STATUS(AE_NO_MEMORY);
        }
 
-       return_ACPI_STATUS(AE_OK);
+       ACPI_MEMCPY(tables, acpi_gbl_root_table_list.tables, new_size);
 
-      error_exit:
-       ACPI_EXCEPTION((AE_INFO, status, "Could not load tables"));
-       return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_load_tables)
+       acpi_gbl_root_table_list.size = acpi_gbl_root_table_list.count;
+       acpi_gbl_root_table_list.tables = tables;
+       acpi_gbl_root_table_list.flags =
+           ACPI_ROOT_ORIGIN_ALLOCATED | ACPI_ROOT_ALLOW_RESIZE;
 
+       return_ACPI_STATUS(AE_OK);
+}
 /*******************************************************************************
  *
  * FUNCTION:    acpi_load_table
@@ -141,342 +219,405 @@ ACPI_EXPORT_SYMBOL(acpi_load_tables)
 acpi_status acpi_load_table(struct acpi_table_header *table_ptr)
 {
        acpi_status status;
-       struct acpi_table_desc table_info;
-       struct acpi_pointer address;
-
-       ACPI_FUNCTION_TRACE(acpi_load_table);
-
-       if (!table_ptr) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
-       /* Copy the table to a local buffer */
+       acpi_native_uint table_index;
+       struct acpi_table_desc table_desc;
 
-       address.pointer_type = ACPI_LOGICAL_POINTER | ACPI_LOGICAL_ADDRESSING;
-       address.pointer.logical = table_ptr;
-
-       status = acpi_tb_get_table_body(&address, table_ptr, &table_info);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
-
-       /* Check signature for a valid table type */
-
-       status = acpi_tb_recognize_table(&table_info, ACPI_TABLE_ALL);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
+       if (!table_ptr)
+               return AE_BAD_PARAMETER;
 
-       /* Install the new table into the local data structures */
+       ACPI_MEMSET(&table_desc, 0, sizeof(struct acpi_table_desc));
+       table_desc.pointer = table_ptr;
+       table_desc.length = table_ptr->length;
+       table_desc.flags = ACPI_TABLE_ORIGIN_UNKNOWN;
 
-       status = acpi_tb_install_table(&table_info);
+       /*
+        * Install the new table into the local data structures
+        */
+       status = acpi_tb_add_table(&table_desc, &table_index);
        if (ACPI_FAILURE(status)) {
-               if (status == AE_ALREADY_EXISTS) {
-
-                       /* Table already exists, no error */
-
-                       status = AE_OK;
-               }
-
-               /* Free table allocated by acpi_tb_get_table_body */
-
-               acpi_tb_delete_single_table(&table_info);
-               return_ACPI_STATUS(status);
+               return status;
        }
+       status = acpi_ns_load_table(table_index, acpi_gbl_root_node);
+       return status;
+}
 
-       /* Convert the table to common format if necessary */
-
-       switch (table_info.type) {
-       case ACPI_TABLE_ID_FADT:
-
-               status = acpi_tb_convert_table_fadt();
-               break;
-
-       case ACPI_TABLE_ID_FACS:
+ACPI_EXPORT_SYMBOL(acpi_load_table)
 
-               status = acpi_tb_build_common_facs(&table_info);
-               break;
+/******************************************************************************
+ *
+ * FUNCTION:    acpi_get_table_header
+ *
+ * PARAMETERS:  Signature           - ACPI signature of needed table
+ *              Instance            - Which instance (for SSDTs)
+ *              out_table_header    - The pointer to the table header to fill
+ *
+ * RETURN:      Status and pointer to mapped table header
+ *
+ * DESCRIPTION: Finds an ACPI table header.
+ *
+ * NOTE:        Caller is responsible in unmapping the header with
+ *              acpi_os_unmap_memory
+ *
+ *****************************************************************************/
+acpi_status
+acpi_get_table_header(char *signature,
+                     acpi_native_uint instance,
+                     struct acpi_table_header *out_table_header)
+{
+       acpi_native_uint i;
+       acpi_native_uint j;
+       struct acpi_table_header *header;
 
-       default:
-               /* Load table into namespace if it contains executable AML */
+       /* Parameter validation */
 
-               status =
-                   acpi_ns_load_table(table_info.installed_desc,
-                                      acpi_gbl_root_node);
-               break;
+       if (!signature || !out_table_header) {
+               return (AE_BAD_PARAMETER);
        }
 
-       if (ACPI_FAILURE(status)) {
+       /*
+        * Walk the root table list
+        */
+       for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) {
+               if (!ACPI_COMPARE_NAME
+                   (&(acpi_gbl_root_table_list.tables[i].signature),
+                    signature)) {
+                       continue;
+               }
 
-               /* Uninstall table and free the buffer */
+               if (++j < instance) {
+                       continue;
+               }
 
-               (void)acpi_tb_uninstall_table(table_info.installed_desc);
+               if (!acpi_gbl_root_table_list.tables[i].pointer) {
+                       if ((acpi_gbl_root_table_list.tables[i].
+                            flags & ACPI_TABLE_ORIGIN_MASK) ==
+                           ACPI_TABLE_ORIGIN_MAPPED) {
+                               header =
+                                   acpi_os_map_memory(acpi_gbl_root_table_list.
+                                                      tables[i].address,
+                                                      sizeof(struct
+                                                             acpi_table_header));
+                               if (!header) {
+                                       return AE_NO_MEMORY;
+                               }
+                               ACPI_MEMCPY(out_table_header, header,
+                                           sizeof(struct acpi_table_header));
+                               acpi_os_unmap_memory(header,
+                                                    sizeof(struct
+                                                           acpi_table_header));
+                       } else {
+                               return AE_NOT_FOUND;
+                       }
+               } else {
+                       ACPI_MEMCPY(out_table_header,
+                                   acpi_gbl_root_table_list.tables[i].pointer,
+                                   sizeof(struct acpi_table_header));
+               }
+               return (AE_OK);
        }
 
-       return_ACPI_STATUS(status);
+       return (AE_NOT_FOUND);
 }
 
-ACPI_EXPORT_SYMBOL(acpi_load_table)
+ACPI_EXPORT_SYMBOL(acpi_get_table_header)
 
-/*******************************************************************************
+
+/******************************************************************************
  *
  * FUNCTION:    acpi_unload_table_id
  *
- * PARAMETERS:  table_type    - Type of table to be unloaded
- *              id            - Owner ID of the table to be removed.
+ * PARAMETERS:  id            - Owner ID of the table to be removed.
  *
  * RETURN:      Status
  *
  * DESCRIPTION: This routine is used to force the unload of a table (by id)
  *
  ******************************************************************************/
-acpi_status acpi_unload_table_id(acpi_table_type table_type, acpi_owner_id id)
+acpi_status acpi_unload_table_id(acpi_owner_id id)
 {
-       struct acpi_table_desc *table_desc;
-       acpi_status status;
+       int i;
+       acpi_status status = AE_NOT_EXIST;
 
        ACPI_FUNCTION_TRACE(acpi_unload_table);
 
-       /* Parameter validation */
-       if (table_type > ACPI_TABLE_ID_MAX)
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-
        /* Find table from the requested type list */
-       table_desc = acpi_gbl_table_lists[table_type].next;
-       while (table_desc && table_desc->owner_id != id)
-               table_desc = table_desc->next;
-
-       if (!table_desc)
-               return_ACPI_STATUS(AE_NOT_EXIST);
-
-       /*
-        * Delete all namespace objects owned by this table. Note that these
-        * objects can appear anywhere in the namespace by virtue of the AML
-        * "Scope" operator. Thus, we need to track ownership by an ID, not
-        * simply a position within the hierarchy
-        */
-       acpi_ns_delete_namespace_by_owner(table_desc->owner_id);
-
-       status = acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
-       if (ACPI_FAILURE(status))
-               return_ACPI_STATUS(status);
-
-       (void)acpi_tb_uninstall_table(table_desc);
-
-       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
-
-       return_ACPI_STATUS(AE_OK);
+       for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+               if (id != acpi_gbl_root_table_list.tables[i].owner_id) {
+                       continue;
+               }
+               /*
+               * Delete all namespace objects owned by this table. Note that these
+               * objects can appear anywhere in the namespace by virtue of the AML
+               * "Scope" operator. Thus, we need to track ownership by an ID, not
+               * simply a position within the hierarchy
+               */
+               acpi_tb_delete_namespace_by_owner(i);
+               acpi_tb_release_owner_id(i);
+               acpi_tb_set_table_loaded_flag(i, FALSE);
+       }
+       return_ACPI_STATUS(status);
 }
 
 ACPI_EXPORT_SYMBOL(acpi_unload_table_id)
 
-#ifdef ACPI_FUTURE_USAGE
 /*******************************************************************************
  *
- * FUNCTION:    acpi_unload_table
+ * FUNCTION:    acpi_get_table
  *
- * PARAMETERS:  table_type    - Type of table to be unloaded
+ * PARAMETERS:  Signature           - ACPI signature of needed table
+ *              Instance            - Which instance (for SSDTs)
+ *              out_table           - Where the pointer to the table is returned
  *
- * RETURN:      Status
+ * RETURN:      Status and pointer to table
  *
- * DESCRIPTION: This routine is used to force the unload of a table
+ * DESCRIPTION: Finds and verifies an ACPI table.
  *
- ******************************************************************************/
-acpi_status acpi_unload_table(acpi_table_type table_type)
+ *****************************************************************************/
+acpi_status
+acpi_get_table(char *signature,
+              acpi_native_uint instance, struct acpi_table_header ** out_table)
 {
-       struct acpi_table_desc *table_desc;
-
-       ACPI_FUNCTION_TRACE(acpi_unload_table);
+       acpi_native_uint i;
+       acpi_native_uint j;
+       acpi_status status;
 
        /* Parameter validation */
 
-       if (table_type > ACPI_TABLE_ID_MAX) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
+       if (!signature || !out_table) {
+               return (AE_BAD_PARAMETER);
        }
 
-       /* Find all tables of the requested type */
+       /*
+        * Walk the root table list
+        */
+       for (i = 0, j = 0; i < acpi_gbl_root_table_list.count; i++) {
+               if (!ACPI_COMPARE_NAME
+                   (&(acpi_gbl_root_table_list.tables[i].signature),
+                    signature)) {
+                       continue;
+               }
 
-       table_desc = acpi_gbl_table_lists[table_type].next;
-       if (!table_desc) {
-               return_ACPI_STATUS(AE_NOT_EXIST);
-       }
+               if (++j < instance) {
+                       continue;
+               }
 
-       while (table_desc) {
-               /*
-                * Delete all namespace objects owned by this table. Note that these
-                * objects can appear anywhere in the namespace by virtue of the AML
-                * "Scope" operator. Thus, we need to track ownership by an ID, not
-                * simply a position within the hierarchy
-                */
-               acpi_ns_delete_namespace_by_owner(table_desc->owner_id);
-               table_desc = table_desc->next;
-       }
+               status =
+                   acpi_tb_verify_table(&acpi_gbl_root_table_list.tables[i]);
+               if (ACPI_SUCCESS(status)) {
+                       *out_table = acpi_gbl_root_table_list.tables[i].pointer;
+               }
 
-       /* Delete (or unmap) all tables of this type */
+               if (!acpi_gbl_permanent_mmap) {
+                       acpi_gbl_root_table_list.tables[i].pointer = 0;
+               }
 
-       acpi_tb_delete_tables_by_type(table_type);
-       return_ACPI_STATUS(AE_OK);
+               return (status);
+       }
+
+       return (AE_NOT_FOUND);
 }
 
-ACPI_EXPORT_SYMBOL(acpi_unload_table)
+ACPI_EXPORT_SYMBOL(acpi_get_table)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_get_table_header
+ * FUNCTION:    acpi_get_table_by_index
  *
- * PARAMETERS:  table_type      - one of the defined table types
- *              Instance        - the non zero instance of the table, allows
- *                                support for multiple tables of the same type
- *                                see acpi_gbl_acpi_table_flag
- *              out_table_header - pointer to the struct acpi_table_header if successful
+ * PARAMETERS:  table_index         - Table index
+ *              Table               - Where the pointer to the table is returned
  *
- * DESCRIPTION: This function is called to get an ACPI table header. The caller
- *              supplies an pointer to a data area sufficient to contain an ACPI
- *              struct acpi_table_header structure.
+ * RETURN:      Status and pointer to the table
  *
- *              The header contains a length field that can be used to determine
- *              the size of the buffer needed to contain the entire table. This
- *              function is not valid for the RSD PTR table since it does not
- *              have a standard header and is fixed length.
+ * DESCRIPTION: Obtain a table by an index into the global table list.
  *
  ******************************************************************************/
 acpi_status
-acpi_get_table_header(acpi_table_type table_type,
-                     u32 instance, struct acpi_table_header *out_table_header)
+acpi_get_table_by_index(acpi_native_uint table_index,
+                       struct acpi_table_header ** table)
 {
-       struct acpi_table_header *tbl_ptr;
        acpi_status status;
 
-       ACPI_FUNCTION_TRACE(acpi_get_table_header);
+       ACPI_FUNCTION_TRACE(acpi_get_table_by_index);
+
+       /* Parameter validation */
 
-       if ((instance == 0) ||
-           (table_type == ACPI_TABLE_ID_RSDP) || (!out_table_header)) {
+       if (!table) {
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
-       /* Check the table type and instance */
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+
+       /* Validate index */
 
-       if ((table_type > ACPI_TABLE_ID_MAX) ||
-           (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) &&
-            instance > 1)) {
+       if (table_index >= acpi_gbl_root_table_list.count) {
+               (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
                return_ACPI_STATUS(AE_BAD_PARAMETER);
        }
 
-       /* Get a pointer to the entire table */
+       if (!acpi_gbl_root_table_list.tables[table_index].pointer) {
 
-       status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
-       }
+               /* Table is not mapped, map it */
 
-       /* The function will return a NULL pointer if the table is not loaded */
-
-       if (tbl_ptr == NULL) {
-               return_ACPI_STATUS(AE_NOT_EXIST);
+               status =
+                   acpi_tb_verify_table(&acpi_gbl_root_table_list.
+                                        tables[table_index]);
+               if (ACPI_FAILURE(status)) {
+                       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+                       return_ACPI_STATUS(status);
+               }
        }
 
-       /* Copy the header to the caller's buffer */
-
-       ACPI_MEMCPY(ACPI_CAST_PTR(void, out_table_header),
-                   ACPI_CAST_PTR(void, tbl_ptr),
-                   sizeof(struct acpi_table_header));
-
-       return_ACPI_STATUS(status);
+       *table = acpi_gbl_root_table_list.tables[table_index].pointer;
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       return_ACPI_STATUS(AE_OK);
 }
 
-ACPI_EXPORT_SYMBOL(acpi_get_table_header)
-#endif                         /*  ACPI_FUTURE_USAGE  */
+ACPI_EXPORT_SYMBOL(acpi_get_table_by_index)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_get_table
+ * FUNCTION:    acpi_tb_load_namespace
  *
- * PARAMETERS:  table_type      - one of the defined table types
- *              Instance        - the non zero instance of the table, allows
- *                                support for multiple tables of the same type
- *                                see acpi_gbl_acpi_table_flag
- *              ret_buffer      - pointer to a structure containing a buffer to
- *                                receive the table
+ * PARAMETERS:  None
  *
  * RETURN:      Status
  *
- * DESCRIPTION: This function is called to get an ACPI table. The caller
- *              supplies an out_buffer large enough to contain the entire ACPI
- *              table. The caller should call the acpi_get_table_header function
- *              first to determine the buffer size needed. Upon completion
- *              the out_buffer->Length field will indicate the number of bytes
- *              copied into the out_buffer->buf_ptr buffer. This table will be
- *              a complete table including the header.
+ * DESCRIPTION: Load the namespace from the DSDT and all SSDTs/PSDTs found in
+ *              the RSDT/XSDT.
  *
  ******************************************************************************/
-acpi_status
-acpi_get_table(acpi_table_type table_type,
-              u32 instance, struct acpi_buffer *ret_buffer)
+static acpi_status acpi_tb_load_namespace(void)
 {
-       struct acpi_table_header *tbl_ptr;
        acpi_status status;
-       acpi_size table_length;
+       struct acpi_table_header *table;
+       acpi_native_uint i;
 
-       ACPI_FUNCTION_TRACE(acpi_get_table);
+       ACPI_FUNCTION_TRACE(tb_load_namespace);
 
-       /* Parameter validation */
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
 
-       if (instance == 0) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
+       /*
+        * Load the namespace. The DSDT is required, but any SSDT and PSDT tables
+        * are optional.
+        */
+       if (!acpi_gbl_root_table_list.count ||
+           !ACPI_COMPARE_NAME(&
+                              (acpi_gbl_root_table_list.
+                               tables[ACPI_TABLE_INDEX_DSDT].signature),
+                              ACPI_SIG_DSDT)
+           ||
+           ACPI_FAILURE(acpi_tb_verify_table
+                        (&acpi_gbl_root_table_list.
+                         tables[ACPI_TABLE_INDEX_DSDT]))) {
+               status = AE_NO_ACPI_TABLES;
+               goto unlock_and_exit;
        }
 
-       status = acpi_ut_validate_buffer(ret_buffer);
-       if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
+       /*
+        * Find DSDT table
+        */
+       status =
+           acpi_os_table_override(acpi_gbl_root_table_list.
+                                  tables[ACPI_TABLE_INDEX_DSDT].pointer,
+                                  &table);
+       if (ACPI_SUCCESS(status) && table) {
+               /*
+                * DSDT table has been found
+                */
+               acpi_tb_delete_table(&acpi_gbl_root_table_list.
+                                    tables[ACPI_TABLE_INDEX_DSDT]);
+               acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].pointer =
+                   table;
+               acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].length =
+                   table->length;
+               acpi_gbl_root_table_list.tables[ACPI_TABLE_INDEX_DSDT].flags =
+                   ACPI_TABLE_ORIGIN_UNKNOWN;
+
+               ACPI_INFO((AE_INFO, "Table DSDT replaced by host OS"));
+               acpi_tb_print_table_header(0, table);
        }
 
-       /* Check the table type and instance */
+       status =
+           acpi_tb_verify_table(&acpi_gbl_root_table_list.
+                                tables[ACPI_TABLE_INDEX_DSDT]);
+       if (ACPI_FAILURE(status)) {
 
-       if ((table_type > ACPI_TABLE_ID_MAX) ||
-           (ACPI_IS_SINGLE_TABLE(acpi_gbl_table_data[table_type].flags) &&
-            instance > 1)) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
+               /* A valid DSDT is required */
+
+               status = AE_NO_ACPI_TABLES;
+               goto unlock_and_exit;
        }
 
-       /* Get a pointer to the entire table */
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
 
-       status = acpi_tb_get_table_ptr(table_type, instance, &tbl_ptr);
+       /*
+        * Load and parse tables.
+        */
+       status = acpi_ns_load_table(ACPI_TABLE_INDEX_DSDT, acpi_gbl_root_node);
        if (ACPI_FAILURE(status)) {
                return_ACPI_STATUS(status);
        }
 
        /*
-        * acpi_tb_get_table_ptr will return a NULL pointer if the
-        * table is not loaded.
+        * Load any SSDT or PSDT tables. Note: Loop leaves tables locked
         */
-       if (tbl_ptr == NULL) {
-               return_ACPI_STATUS(AE_NOT_EXIST);
+       (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
+       for (i = 0; i < acpi_gbl_root_table_list.count; ++i) {
+               if ((!ACPI_COMPARE_NAME
+                    (&(acpi_gbl_root_table_list.tables[i].signature),
+                     ACPI_SIG_SSDT)
+                    &&
+                    !ACPI_COMPARE_NAME(&
+                                       (acpi_gbl_root_table_list.tables[i].
+                                        signature), ACPI_SIG_PSDT))
+                   ||
+                   ACPI_FAILURE(acpi_tb_verify_table
+                                (&acpi_gbl_root_table_list.tables[i]))) {
+                       continue;
+               }
+
+               /* Ignore errors while loading tables, get as many as possible */
+
+               (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+               (void)acpi_ns_load_table(i, acpi_gbl_root_node);
+               (void)acpi_ut_acquire_mutex(ACPI_MTX_TABLES);
        }
 
-       /* Get the table length */
+       ACPI_DEBUG_PRINT((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
 
-       if (table_type == ACPI_TABLE_ID_RSDP) {
+      unlock_and_exit:
+       (void)acpi_ut_release_mutex(ACPI_MTX_TABLES);
+       return_ACPI_STATUS(status);
+}
 
-               /* RSD PTR is the only "table" without a header */
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_load_tables
+ *
+ * PARAMETERS:  None
+ *
+ * RETURN:      Status
+ *
+ * DESCRIPTION: Load the ACPI tables from the RSDT/XSDT
+ *
+ ******************************************************************************/
 
-               table_length = sizeof(struct rsdp_descriptor);
-       } else {
-               table_length = (acpi_size) tbl_ptr->length;
-       }
+acpi_status acpi_load_tables(void)
+{
+       acpi_status status;
 
-       /* Validate/Allocate/Clear caller buffer */
+       ACPI_FUNCTION_TRACE(acpi_load_tables);
 
-       status = acpi_ut_initialize_buffer(ret_buffer, table_length);
+       /*
+        * Load the namespace from the tables
+        */
+       status = acpi_tb_load_namespace();
        if (ACPI_FAILURE(status)) {
-               return_ACPI_STATUS(status);
+               ACPI_EXCEPTION((AE_INFO, status,
+                               "While loading namespace from ACPI tables"));
        }
 
-       /* Copy the table to the buffer */
-
-       ACPI_MEMCPY(ACPI_CAST_PTR(void, ret_buffer->pointer),
-                   ACPI_CAST_PTR(void, tbl_ptr), table_length);
-
-       return_ACPI_STATUS(AE_OK);
+       return_ACPI_STATUS(status);
 }
 
-ACPI_EXPORT_SYMBOL(acpi_get_table)
+ACPI_EXPORT_SYMBOL(acpi_load_tables)
index da2648b..cf8fa51 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 ACPI_MODULE_NAME("tbxfroot")
 
 /* Local prototypes */
-static acpi_status
-acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags);
-
 static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
 
+static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp);
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_tb_validate_rsdp
  *
- * PARAMETERS:  Rsdp        - Pointer to unvalidated RSDP
+ * PARAMETERS:  Rsdp                - Pointer to unvalidated RSDP
  *
  * RETURN:      Status
  *
@@ -65,14 +64,18 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length);
  *
  ******************************************************************************/
 
-acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
+static acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)
 {
        ACPI_FUNCTION_ENTRY();
 
        /*
-        *  The signature and checksum must both be correct
+        * The signature and checksum must both be correct
+        *
+        * Note: Sometimes there exists more than one RSDP in memory; the valid
+        * RSDP has a valid checksum, all others have an invalid checksum.
         */
-       if (ACPI_STRNCMP((char *)rsdp, RSDP_SIG, sizeof(RSDP_SIG) - 1) != 0) {
+       if (ACPI_STRNCMP((char *)rsdp, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)
+           != 0) {
 
                /* Nope, BAD Signature */
 
@@ -81,14 +84,14 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
 
        /* Check the standard checksum */
 
-       if (acpi_tb_sum_table(rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
+       if (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {
                return (AE_BAD_CHECKSUM);
        }
 
        /* Check extended checksum if table version >= 2 */
 
        if ((rsdp->revision >= 2) &&
-           (acpi_tb_sum_table(rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
+           (acpi_tb_checksum((u8 *) rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {
                return (AE_BAD_CHECKSUM);
        }
 
@@ -97,314 +100,123 @@ acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp)
 
 /*******************************************************************************
  *
- * FUNCTION:    acpi_tb_find_table
- *
- * PARAMETERS:  Signature           - String with ACPI table signature
- *              oem_id              - String with the table OEM ID
- *              oem_table_id        - String with the OEM Table ID
- *              table_ptr           - Where the table pointer is returned
- *
- * RETURN:      Status
+ * FUNCTION:    acpi_tb_find_rsdp
  *
- * DESCRIPTION: Find an ACPI table (in the RSDT/XSDT) that matches the
- *              Signature, OEM ID and OEM Table ID.
+ * PARAMETERS:  table_address           - Where the table pointer is returned
  *
- ******************************************************************************/
-
-acpi_status
-acpi_tb_find_table(char *signature,
-                  char *oem_id,
-                  char *oem_table_id, struct acpi_table_header ** table_ptr)
-{
-       acpi_status status;
-       struct acpi_table_header *table;
-
-       ACPI_FUNCTION_TRACE(tb_find_table);
-
-       /* Validate string lengths */
-
-       if ((ACPI_STRLEN(signature) > ACPI_NAME_SIZE) ||
-           (ACPI_STRLEN(oem_id) > sizeof(table->oem_id)) ||
-           (ACPI_STRLEN(oem_table_id) > sizeof(table->oem_table_id))) {
-               return_ACPI_STATUS(AE_AML_STRING_LIMIT);
-       }
-
-       if (ACPI_COMPARE_NAME(signature, DSDT_SIG)) {
-               /*
-                * The DSDT pointer is contained in the FADT, not the RSDT.
-                * This code should suffice, because the only code that would perform
-                * a "find" on the DSDT is the data_table_region() AML opcode -- in
-                * which case, the DSDT is guaranteed to be already loaded.
-                * If this becomes insufficient, the FADT will have to be found first.
-                */
-               if (!acpi_gbl_DSDT) {
-                       return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-               }
-               table = acpi_gbl_DSDT;
-       } else {
-               /* Find the table */
-
-               status = acpi_get_firmware_table(signature, 1,
-                                                ACPI_LOGICAL_ADDRESSING,
-                                                &table);
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
-               }
-       }
-
-       /* Check oem_id and oem_table_id */
-
-       if ((oem_id[0] &&
-            ACPI_STRNCMP(oem_id, table->oem_id,
-                         sizeof(table->oem_id))) ||
-           (oem_table_id[0] &&
-            ACPI_STRNCMP(oem_table_id, table->oem_table_id,
-                         sizeof(table->oem_table_id)))) {
-               return_ACPI_STATUS(AE_AML_NAME_NOT_FOUND);
-       }
-
-       ACPI_DEBUG_PRINT((ACPI_DB_TABLES, "Found table [%4.4s]\n",
-                         table->signature));
-
-       *table_ptr = table;
-       return_ACPI_STATUS(AE_OK);
-}
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_get_firmware_table
+ * RETURN:      Status, RSDP physical address
  *
- * PARAMETERS:  Signature       - Any ACPI table signature
- *              Instance        - the non zero instance of the table, allows
- *                                support for multiple tables of the same type
- *              Flags           - Physical/Virtual support
- *              table_pointer   - Where a buffer containing the table is
- *                                returned
+ * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
+ *              pointer structure.  If it is found, set *RSDP to point to it.
  *
- * RETURN:      Status
+ * NOTE1:       The RSDP must be either in the first 1_k of the Extended
+ *              BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
+ *              Only a 32-bit physical address is necessary.
  *
- * DESCRIPTION: This function is called to get an ACPI table. A buffer is
- *              allocated for the table and returned in table_pointer.
- *              This table will be a complete table including the header.
+ * NOTE2:       This function is always available, regardless of the
+ *              initialization state of the rest of ACPI.
  *
  ******************************************************************************/
 
-acpi_status
-acpi_get_firmware_table(acpi_string signature,
-                       u32 instance,
-                       u32 flags, struct acpi_table_header **table_pointer)
+acpi_status acpi_find_root_pointer(acpi_native_uint * table_address)
 {
-       acpi_status status;
-       struct acpi_pointer address;
-       struct acpi_table_header *header = NULL;
-       struct acpi_table_desc *table_info = NULL;
-       struct acpi_table_desc *rsdt_info;
-       u32 table_count;
-       u32 i;
-       u32 j;
-
-       ACPI_FUNCTION_TRACE(acpi_get_firmware_table);
-
-       /*
-        * Ensure that at least the table manager is initialized.  We don't
-        * require that the entire ACPI subsystem is up for this interface.
-        * If we have a buffer, we must have a length too
-        */
-       if ((instance == 0) || (!signature) || (!table_pointer)) {
-               return_ACPI_STATUS(AE_BAD_PARAMETER);
-       }
-
-       /* Ensure that we have a RSDP */
-
-       if (!acpi_gbl_RSDP) {
-
-               /* Get the RSDP */
-
-               status = acpi_os_get_root_pointer(flags, &address);
-               if (ACPI_FAILURE(status)) {
-                       ACPI_DEBUG_PRINT((ACPI_DB_INFO, "RSDP not found\n"));
-                       return_ACPI_STATUS(AE_NO_ACPI_TABLES);
-               }
-
-               /* Map and validate the RSDP */
-
-               if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
-                       status = acpi_os_map_memory(address.pointer.physical,
-                                                   sizeof(struct
-                                                          rsdp_descriptor),
-                                                   (void *)&acpi_gbl_RSDP);
-                       if (ACPI_FAILURE(status)) {
-                               return_ACPI_STATUS(status);
-                       }
-               } else {
-                       acpi_gbl_RSDP = address.pointer.logical;
-               }
-
-               /* The RDSP signature and checksum must both be correct */
-
-               status = acpi_tb_validate_rsdp(acpi_gbl_RSDP);
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
-               }
-       }
-
-       /* Get the RSDT address via the RSDP */
-
-       acpi_tb_get_rsdt_address(&address);
-       ACPI_DEBUG_PRINT((ACPI_DB_INFO,
-                         "RSDP located at %p, RSDT physical=%8.8X%8.8X\n",
-                         acpi_gbl_RSDP,
-                         ACPI_FORMAT_UINT64(address.pointer.value)));
+       u8 *table_ptr;
+       u8 *mem_rover;
+       u32 physical_address;
 
-       /* Insert processor_mode flags */
+       ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
 
-       address.pointer_type |= flags;
+       /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
 
-       /* Get and validate the RSDT */
+       table_ptr = acpi_os_map_memory((acpi_physical_address)
+                                      ACPI_EBDA_PTR_LOCATION,
+                                      ACPI_EBDA_PTR_LENGTH);
+       if (!table_ptr) {
+               ACPI_ERROR((AE_INFO,
+                           "Could not map memory at %8.8X for length %X",
+                           ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH));
 
-       rsdt_info = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_table_desc));
-       if (!rsdt_info) {
                return_ACPI_STATUS(AE_NO_MEMORY);
        }
 
-       status = acpi_tb_get_table(&address, rsdt_info);
-       if (ACPI_FAILURE(status)) {
-               goto cleanup;
-       }
-
-       status = acpi_tb_validate_rsdt(rsdt_info->pointer);
-       if (ACPI_FAILURE(status)) {
-               goto cleanup;
-       }
+       ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
 
-       /* Allocate a scratch table header and table descriptor */
+       /* Convert segment part to physical address */
 
-       header = ACPI_ALLOCATE(sizeof(struct acpi_table_header));
-       if (!header) {
-               status = AE_NO_MEMORY;
-               goto cleanup;
-       }
+       physical_address <<= 4;
+       acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
 
-       table_info = ACPI_ALLOCATE(sizeof(struct acpi_table_desc));
-       if (!table_info) {
-               status = AE_NO_MEMORY;
-               goto cleanup;
-       }
+       /* EBDA present? */
 
-       /* Get the number of table pointers within the RSDT */
-
-       table_count =
-           acpi_tb_get_table_count(acpi_gbl_RSDP, rsdt_info->pointer);
-       address.pointer_type = acpi_gbl_table_flags | flags;
-
-       /*
-        * Search the RSDT/XSDT for the correct instance of the
-        * requested table
-        */
-       for (i = 0, j = 0; i < table_count; i++) {
+       if (physical_address > 0x400) {
                /*
-                * Get the next table pointer, handle RSDT vs. XSDT
-                * RSDT pointers are 32 bits, XSDT pointers are 64 bits
+                * 1b) Search EBDA paragraphs (EBDA is required to be a
+                *     minimum of 1_k length)
                 */
-               if (acpi_gbl_root_table_type == ACPI_TABLE_TYPE_RSDT) {
-                       address.pointer.value =
-                           (ACPI_CAST_PTR
-                            (struct rsdt_descriptor,
-                             rsdt_info->pointer))->table_offset_entry[i];
-               } else {
-                       address.pointer.value =
-                           (ACPI_CAST_PTR
-                            (struct xsdt_descriptor,
-                             rsdt_info->pointer))->table_offset_entry[i];
-               }
-
-               /* Get the table header */
+               table_ptr = acpi_os_map_memory((acpi_native_uint)
+                                              physical_address,
+                                              ACPI_EBDA_WINDOW_SIZE);
+               if (!table_ptr) {
+                       ACPI_ERROR((AE_INFO,
+                                   "Could not map memory at %8.8X for length %X",
+                                   physical_address, ACPI_EBDA_WINDOW_SIZE));
 
-               status = acpi_tb_get_table_header(&address, header);
-               if (ACPI_FAILURE(status)) {
-                       goto cleanup;
+                       return_ACPI_STATUS(AE_NO_MEMORY);
                }
 
-               /* Compare table signatures and table instance */
-
-               if (ACPI_COMPARE_NAME(header->signature, signature)) {
-
-                       /* An instance of the table was found */
+               mem_rover =
+                   acpi_tb_scan_memory_for_rsdp(table_ptr,
+                                                ACPI_EBDA_WINDOW_SIZE);
+               acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
 
-                       j++;
-                       if (j >= instance) {
+               if (mem_rover) {
 
-                               /* Found the correct instance, get the entire table */
+                       /* Return the physical address */
 
-                               status =
-                                   acpi_tb_get_table_body(&address, header,
-                                                          table_info);
-                               if (ACPI_FAILURE(status)) {
-                                       goto cleanup;
-                               }
+                       physical_address +=
+                           (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
 
-                               *table_pointer = table_info->pointer;
-                               goto cleanup;
-                       }
+                       *table_address = physical_address;
+                       return_ACPI_STATUS(AE_OK);
                }
        }
 
-       /* Did not find the table */
+       /*
+        * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
+        */
+       table_ptr = acpi_os_map_memory((acpi_physical_address)
+                                      ACPI_HI_RSDP_WINDOW_BASE,
+                                      ACPI_HI_RSDP_WINDOW_SIZE);
 
-       status = AE_NOT_EXIST;
+       if (!table_ptr) {
+               ACPI_ERROR((AE_INFO,
+                           "Could not map memory at %8.8X for length %X",
+                           ACPI_HI_RSDP_WINDOW_BASE,
+                           ACPI_HI_RSDP_WINDOW_SIZE));
 
-      cleanup:
-       if (rsdt_info->pointer) {
-               acpi_os_unmap_memory(rsdt_info->pointer,
-                                    (acpi_size) rsdt_info->pointer->length);
+               return_ACPI_STATUS(AE_NO_MEMORY);
        }
-       ACPI_FREE(rsdt_info);
 
-       if (header) {
-               ACPI_FREE(header);
-       }
-       if (table_info) {
-               ACPI_FREE(table_info);
-       }
-       return_ACPI_STATUS(status);
-}
+       mem_rover =
+           acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
+       acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
 
-ACPI_EXPORT_SYMBOL(acpi_get_firmware_table)
+       if (mem_rover) {
 
-/* TBD: Move to a new file */
-#if ACPI_MACHINE_WIDTH != 16
-/*******************************************************************************
- *
- * FUNCTION:    acpi_find_root_pointer
- *
- * PARAMETERS:  Flags                   - Logical/Physical addressing
- *              rsdp_address            - Where to place the RSDP address
- *
- * RETURN:      Status, Physical address of the RSDP
- *
- * DESCRIPTION: Find the RSDP
- *
- ******************************************************************************/
-acpi_status acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address)
-{
-       struct acpi_table_desc table_info;
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
-
-       /* Get the RSDP */
+               /* Return the physical address */
 
-       status = acpi_tb_find_rsdp(&table_info, flags);
-       if (ACPI_FAILURE(status)) {
-               ACPI_EXCEPTION((AE_INFO, status,
-                               "RSDP structure not found - Flags=%X", flags));
+               physical_address = (u32)
+                   (ACPI_HI_RSDP_WINDOW_BASE +
+                    ACPI_PTR_DIFF(mem_rover, table_ptr));
 
-               return_ACPI_STATUS(AE_NO_ACPI_TABLES);
+               *table_address = physical_address;
+               return_ACPI_STATUS(AE_OK);
        }
 
-       rsdp_address->pointer_type = ACPI_PHYSICAL_POINTER;
-       rsdp_address->pointer.physical = table_info.physical_address;
-       return_ACPI_STATUS(AE_OK);
+       /* A valid RSDP was not found */
+
+       ACPI_ERROR((AE_INFO, "A valid RSDP was not found"));
+       return_ACPI_STATUS(AE_NOT_FOUND);
 }
 
 ACPI_EXPORT_SYMBOL(acpi_find_root_pointer)
@@ -440,7 +252,7 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
 
                status =
                    acpi_tb_validate_rsdp(ACPI_CAST_PTR
-                                         (struct rsdp_descriptor, mem_rover));
+                                         (struct acpi_table_rsdp, mem_rover));
                if (ACPI_SUCCESS(status)) {
 
                        /* Sig and checksum valid, we have found a real RSDP */
@@ -461,189 +273,3 @@ static u8 *acpi_tb_scan_memory_for_rsdp(u8 * start_address, u32 length)
                          start_address));
        return_PTR(NULL);
 }
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_tb_find_rsdp
- *
- * PARAMETERS:  table_info              - Where the table info is returned
- *              Flags                   - Current memory mode (logical vs.
- *                                        physical addressing)
- *
- * RETURN:      Status, RSDP physical address
- *
- * DESCRIPTION: Search lower 1_mbyte of memory for the root system descriptor
- *              pointer structure.  If it is found, set *RSDP to point to it.
- *
- *              NOTE1: The RSDP must be either in the first 1_k of the Extended
- *              BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)
- *              Only a 32-bit physical address is necessary.
- *
- *              NOTE2: This function is always available, regardless of the
- *              initialization state of the rest of ACPI.
- *
- ******************************************************************************/
-
-static acpi_status
-acpi_tb_find_rsdp(struct acpi_table_desc *table_info, u32 flags)
-{
-       u8 *table_ptr;
-       u8 *mem_rover;
-       u32 physical_address;
-       acpi_status status;
-
-       ACPI_FUNCTION_TRACE(tb_find_rsdp);
-
-       /*
-        * Scan supports either logical addressing or physical addressing
-        */
-       if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
-
-               /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
-
-               status = acpi_os_map_memory((acpi_physical_address)
-                                           ACPI_EBDA_PTR_LOCATION,
-                                           ACPI_EBDA_PTR_LENGTH,
-                                           (void *)&table_ptr);
-               if (ACPI_FAILURE(status)) {
-                       ACPI_ERROR((AE_INFO,
-                                   "Could not map memory at %8.8X for length %X",
-                                   ACPI_EBDA_PTR_LOCATION,
-                                   ACPI_EBDA_PTR_LENGTH));
-
-                       return_ACPI_STATUS(status);
-               }
-
-               ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
-
-               /* Convert segment part to physical address */
-
-               physical_address <<= 4;
-               acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
-
-               /* EBDA present? */
-
-               if (physical_address > 0x400) {
-                       /*
-                        * 1b) Search EBDA paragraphs (EBDA is required to be a
-                        *     minimum of 1_k length)
-                        */
-                       status = acpi_os_map_memory((acpi_physical_address)
-                                                   physical_address,
-                                                   ACPI_EBDA_WINDOW_SIZE,
-                                                   (void *)&table_ptr);
-                       if (ACPI_FAILURE(status)) {
-                               ACPI_ERROR((AE_INFO,
-                                           "Could not map memory at %8.8X for length %X",
-                                           physical_address,
-                                           ACPI_EBDA_WINDOW_SIZE));
-
-                               return_ACPI_STATUS(status);
-                       }
-
-                       mem_rover = acpi_tb_scan_memory_for_rsdp(table_ptr,
-                                                                ACPI_EBDA_WINDOW_SIZE);
-                       acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
-
-                       if (mem_rover) {
-
-                               /* Return the physical address */
-
-                               physical_address +=
-                                   (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
-
-                               table_info->physical_address =
-                                   (acpi_physical_address) physical_address;
-                               return_ACPI_STATUS(AE_OK);
-                       }
-               }
-
-               /*
-                * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
-                */
-               status = acpi_os_map_memory((acpi_physical_address)
-                                           ACPI_HI_RSDP_WINDOW_BASE,
-                                           ACPI_HI_RSDP_WINDOW_SIZE,
-                                           (void *)&table_ptr);
-
-               if (ACPI_FAILURE(status)) {
-                       ACPI_ERROR((AE_INFO,
-                                   "Could not map memory at %8.8X for length %X",
-                                   ACPI_HI_RSDP_WINDOW_BASE,
-                                   ACPI_HI_RSDP_WINDOW_SIZE));
-
-                       return_ACPI_STATUS(status);
-               }
-
-               mem_rover =
-                   acpi_tb_scan_memory_for_rsdp(table_ptr,
-                                                ACPI_HI_RSDP_WINDOW_SIZE);
-               acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
-
-               if (mem_rover) {
-
-                       /* Return the physical address */
-
-                       physical_address = (u32)
-                           (ACPI_HI_RSDP_WINDOW_BASE +
-                            ACPI_PTR_DIFF(mem_rover, table_ptr));
-
-                       table_info->physical_address =
-                           (acpi_physical_address) physical_address;
-                       return_ACPI_STATUS(AE_OK);
-               }
-       }
-
-       /*
-        * Physical addressing
-        */
-       else {
-               /* 1a) Get the location of the EBDA */
-
-               ACPI_MOVE_16_TO_32(&physical_address, ACPI_EBDA_PTR_LOCATION);
-               physical_address <<= 4; /* Convert segment to physical address */
-
-               /* EBDA present? */
-
-               if (physical_address > 0x400) {
-                       /*
-                        * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of
-                        *     1_k length)
-                        */
-                       mem_rover =
-                           acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR
-                                                        (physical_address),
-                                                        ACPI_EBDA_WINDOW_SIZE);
-                       if (mem_rover) {
-
-                               /* Return the physical address */
-
-                               table_info->physical_address =
-                                   ACPI_TO_INTEGER(mem_rover);
-                               return_ACPI_STATUS(AE_OK);
-                       }
-               }
-
-               /* 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh */
-
-               mem_rover =
-                   acpi_tb_scan_memory_for_rsdp(ACPI_PHYSADDR_TO_PTR
-                                                (ACPI_HI_RSDP_WINDOW_BASE),
-                                                ACPI_HI_RSDP_WINDOW_SIZE);
-               if (mem_rover) {
-
-                       /* Found it, return the physical address */
-
-                       table_info->physical_address =
-                           ACPI_TO_INTEGER(mem_rover);
-                       return_ACPI_STATUS(AE_OK);
-               }
-       }
-
-       /* A valid RSDP was not found */
-
-       ACPI_ERROR((AE_INFO, "No valid RSDP was found"));
-       return_ACPI_STATUS(AE_NOT_FOUND);
-}
-
-#endif
index 40ddb4d..f76d316 100644 (file)
@@ -82,7 +82,7 @@ MODULE_PARM_DESC(tzp, "Thermal zone polling frequency, in 1/10 seconds.\n");
 
 static int acpi_thermal_add(struct acpi_device *device);
 static int acpi_thermal_remove(struct acpi_device *device, int type);
-static int acpi_thermal_resume(struct acpi_device *device, int state);
+static int acpi_thermal_resume(struct acpi_device *device);
 static int acpi_thermal_state_open_fs(struct inode *inode, struct file *file);
 static int acpi_thermal_temp_open_fs(struct inode *inode, struct file *file);
 static int acpi_thermal_trip_open_fs(struct inode *inode, struct file *file);
@@ -1353,7 +1353,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
        return 0;
 }
 
-static int acpi_thermal_resume(struct acpi_device *device, int state)
+static int acpi_thermal_resume(struct acpi_device *device)
 {
        struct acpi_thermal *tz = NULL;
        int i;
index f6cbc0b..55a7648 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,7 @@
  */
 
 #include <acpi/acpi.h>
+#include <acpi/acdebug.h>
 
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utalloc")
@@ -142,6 +143,14 @@ acpi_status acpi_ut_create_caches(void)
 
 acpi_status acpi_ut_delete_caches(void)
 {
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+       char buffer[7];
+
+       if (acpi_gbl_display_final_mem_stats) {
+               ACPI_STRCPY(buffer, "MEMORY");
+               acpi_db_display_statistics(buffer);
+       }
+#endif
 
        (void)acpi_os_delete_cache(acpi_gbl_namespace_cache);
        acpi_gbl_namespace_cache = NULL;
index 1a1f810..870f6ed 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -289,6 +289,14 @@ void *acpi_os_acquire_object(struct acpi_memory_list *cache)
 
                ACPI_MEM_TRACKING(cache->total_allocated++);
 
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+               if ((cache->total_allocated - cache->total_freed) >
+                   cache->max_occupied) {
+                       cache->max_occupied =
+                           cache->total_allocated - cache->total_freed;
+               }
+#endif
+
                /* Avoid deadlock with ACPI_ALLOCATE_ZEROED */
 
                status = acpi_ut_release_mutex(ACPI_MTX_CACHES);
index 5e1a80d..84d529d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -719,6 +719,15 @@ acpi_ut_copy_simple_object(union acpi_operand_object *source_desc,
                acpi_ut_add_reference(source_desc->reference.object);
                break;
 
+       case ACPI_TYPE_REGION:
+               /*
+                * We copied the Region Handler, so we now must add a reference
+                */
+               if (dest_desc->region.handler) {
+                       acpi_ut_add_reference(dest_desc->region.handler);
+               }
+               break;
+
        default:
                /* Nothing to do for other simple objects */
                break;
index 9e9054e..61ad4f2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -181,8 +181,7 @@ acpi_ut_debug_print(u32 requested_debug_level,
                if (ACPI_LV_THREADS & acpi_dbg_level) {
                        acpi_os_printf
                            ("\n**** Context Switch from TID %lX to TID %lX ****\n\n",
-                            (unsigned long) acpi_gbl_prev_thread_id,
-                            (unsigned long) thread_id);
+                            (unsigned long)acpi_gbl_prev_thread_id, (unsigned long)thread_id);
                }
 
                acpi_gbl_prev_thread_id = thread_id;
@@ -195,7 +194,7 @@ acpi_ut_debug_print(u32 requested_debug_level,
        acpi_os_printf("%8s-%04ld ", module_name, line_number);
 
        if (ACPI_LV_THREADS & acpi_dbg_level) {
-               acpi_os_printf("[%04lX] ", thread_id);
+               acpi_os_printf("[%04lX] ", (unsigned long)thread_id);
        }
 
        acpi_os_printf("[%02ld] %-22.22s: ",
index 9d3f114..f777ceb 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -158,16 +158,20 @@ static void acpi_ut_delete_internal_obj(union acpi_operand_object *object)
                                  "***** Mutex %p, OS Mutex %p\n",
                                  object, object->mutex.os_mutex));
 
-               if (object->mutex.os_mutex != ACPI_GLOBAL_LOCK) {
-                       acpi_ex_unlink_mutex(object);
-                       acpi_os_delete_mutex(object->mutex.os_mutex);
-               } else {
-                       /* Global Lock "mutex" is actually a counting semaphore */
+               if (object->mutex.os_mutex == acpi_gbl_global_lock_mutex) {
+
+                       /* Global Lock has extra semaphore */
 
                        (void)
                            acpi_os_delete_semaphore
                            (acpi_gbl_global_lock_semaphore);
                        acpi_gbl_global_lock_semaphore = NULL;
+
+                       acpi_os_delete_mutex(object->mutex.os_mutex);
+                       acpi_gbl_global_lock_mutex = NULL;
+               } else {
+                       acpi_ex_unlink_mutex(object);
+                       acpi_os_delete_mutex(object->mutex.os_mutex);
                }
                break;
 
index d6d7121..13d5879 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 014030a..af33358 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
 
+ACPI_EXPORT_SYMBOL(acpi_gbl_FADT)
 #define _COMPONENT          ACPI_UTILITIES
-ACPI_MODULE_NAME("utglobal")
-
-/*******************************************************************************
- *
- * FUNCTION:    acpi_format_exception
- *
- * PARAMETERS:  Status       - The acpi_status code to be formatted
- *
- * RETURN:      A string containing the exception text. A valid pointer is
- *              always returned.
- *
- * DESCRIPTION: This function translates an ACPI exception into an ASCII string.
- *
- ******************************************************************************/
-const char *acpi_format_exception(acpi_status status)
-{
-       acpi_status sub_status;
-       const char *exception = NULL;
-
-       ACPI_FUNCTION_ENTRY();
-
-       /*
-        * Status is composed of two parts, a "type" and an actual code
-        */
-       sub_status = (status & ~AE_CODE_MASK);
-
-       switch (status & AE_CODE_MASK) {
-       case AE_CODE_ENVIRONMENTAL:
-
-               if (sub_status <= AE_CODE_ENV_MAX) {
-                       exception = acpi_gbl_exception_names_env[sub_status];
-               }
-               break;
-
-       case AE_CODE_PROGRAMMER:
-
-               if (sub_status <= AE_CODE_PGM_MAX) {
-                       exception =
-                           acpi_gbl_exception_names_pgm[sub_status - 1];
-               }
-               break;
-
-       case AE_CODE_ACPI_TABLES:
-
-               if (sub_status <= AE_CODE_TBL_MAX) {
-                       exception =
-                           acpi_gbl_exception_names_tbl[sub_status - 1];
-               }
-               break;
-
-       case AE_CODE_AML:
-
-               if (sub_status <= AE_CODE_AML_MAX) {
-                       exception =
-                           acpi_gbl_exception_names_aml[sub_status - 1];
-               }
-               break;
-
-       case AE_CODE_CONTROL:
-
-               if (sub_status <= AE_CODE_CTRL_MAX) {
-                       exception =
-                           acpi_gbl_exception_names_ctrl[sub_status - 1];
-               }
-               break;
-
-       default:
-               break;
-       }
-
-       if (!exception) {
-
-               /* Exception code was not recognized */
-
-               ACPI_ERROR((AE_INFO,
-                           "Unknown exception code: 0x%8.8X", status));
-
-               exception = "UNKNOWN_STATUS_CODE";
-       }
-
-       return (ACPI_CAST_PTR(const char, exception));
-}
+    ACPI_MODULE_NAME("utglobal")
 
 /*******************************************************************************
  *
@@ -163,8 +83,6 @@ u32 acpi_gbl_startup_flags = 0;
 
 u8 acpi_gbl_shutdown = TRUE;
 
-const u8 acpi_gbl_decode_to8bit[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };
-
 const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT] = {
        "\\_S0_",
        "\\_S1_",
@@ -183,10 +101,45 @@ const char *acpi_gbl_highest_dstate_names[4] = {
 
 /*******************************************************************************
  *
- * Namespace globals
+ * FUNCTION:    acpi_format_exception
+ *
+ * PARAMETERS:  Status       - The acpi_status code to be formatted
+ *
+ * RETURN:      A string containing the exception text. A valid pointer is
+ *              always returned.
+ *
+ * DESCRIPTION: This function translates an ACPI exception into an ASCII string
+ *              It is here instead of utxface.c so it is always present.
  *
  ******************************************************************************/
 
+const char *acpi_format_exception(acpi_status status)
+{
+       const char *exception = NULL;
+
+       ACPI_FUNCTION_ENTRY();
+
+       exception = acpi_ut_validate_exception(status);
+       if (!exception) {
+
+               /* Exception code was not recognized */
+
+               ACPI_ERROR((AE_INFO,
+                           "Unknown exception code: 0x%8.8X", status));
+
+               exception = "UNKNOWN_STATUS_CODE";
+       }
+
+       return (ACPI_CAST_PTR(const char, exception));
+}
+
+ACPI_EXPORT_SYMBOL(acpi_format_exception)
+
+/*******************************************************************************
+ *
+ * Namespace globals
+ *
+ ******************************************************************************/
 /*
  * Predefined ACPI Names (Built-in to the Interpreter)
  *
@@ -280,53 +233,6 @@ char acpi_ut_hex_to_ascii_char(acpi_integer integer, u32 position)
        return (acpi_gbl_hex_to_ascii[(integer >> position) & 0xF]);
 }
 
-/*******************************************************************************
- *
- * Table name globals
- *
- * NOTE: This table includes ONLY the ACPI tables that the subsystem consumes.
- * it is NOT an exhaustive list of all possible ACPI tables.  All ACPI tables
- * that are not used by the subsystem are simply ignored.
- *
- * Do NOT add any table to this list that is not consumed directly by this
- * subsystem (No MADT, ECDT, SBST, etc.)
- *
- ******************************************************************************/
-
-struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1];
-
-struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1] = {
-       /***********    Name,   Signature, Global typed pointer     Signature size,      Type                  How many allowed?,    Contains valid AML? */
-
-       /* RSDP 0 */ {RSDP_NAME, RSDP_SIG, NULL, sizeof(RSDP_SIG) - 1,
-                     ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}
-       ,
-       /* DSDT 1 */ {DSDT_SIG, DSDT_SIG, (void *)&acpi_gbl_DSDT,
-                     sizeof(DSDT_SIG) - 1,
-                     ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE |
-                     ACPI_TABLE_EXECUTABLE}
-       ,
-       /* FADT 2 */ {FADT_SIG, FADT_SIG, (void *)&acpi_gbl_FADT,
-                     sizeof(FADT_SIG) - 1,
-                     ACPI_TABLE_PRIMARY | ACPI_TABLE_SINGLE}
-       ,
-       /* FACS 3 */ {FACS_SIG, FACS_SIG, (void *)&acpi_gbl_FACS,
-                     sizeof(FACS_SIG) - 1,
-                     ACPI_TABLE_SECONDARY | ACPI_TABLE_SINGLE}
-       ,
-       /* PSDT 4 */ {PSDT_SIG, PSDT_SIG, NULL, sizeof(PSDT_SIG) - 1,
-                     ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE |
-                     ACPI_TABLE_EXECUTABLE}
-       ,
-       /* SSDT 5 */ {SSDT_SIG, SSDT_SIG, NULL, sizeof(SSDT_SIG) - 1,
-                     ACPI_TABLE_PRIMARY | ACPI_TABLE_MULTIPLE |
-                     ACPI_TABLE_EXECUTABLE}
-       ,
-       /* XSDT 6 */ {XSDT_SIG, XSDT_SIG, NULL, sizeof(RSDT_SIG) - 1,
-                     ACPI_TABLE_ROOT | ACPI_TABLE_SINGLE}
-       ,
-};
-
 /******************************************************************************
  *
  * Event and Hardware globals
@@ -612,7 +518,7 @@ char *acpi_ut_get_node_name(void *object)
        /* Name must be a valid ACPI name */
 
        if (!acpi_ut_valid_acpi_name(node->name.integer)) {
-               node->name.integer = acpi_ut_repair_name(node->name.integer);
+               node->name.integer = acpi_ut_repair_name(node->name.ascii);
        }
 
        /* Return the name */
@@ -751,13 +657,6 @@ void acpi_ut_init_globals(void)
                return;
        }
 
-       /* ACPI table structure */
-
-       for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
-               acpi_gbl_table_lists[i].next = NULL;
-               acpi_gbl_table_lists[i].count = 0;
-       }
-
        /* Mutex locked flags */
 
        for (i = 0; i < ACPI_NUM_MUTEX; i++) {
@@ -773,6 +672,7 @@ void acpi_ut_init_globals(void)
 
        /* GPE support */
 
+       acpi_gpe_count = 0;
        acpi_gbl_gpe_xrupt_list_head = NULL;
        acpi_gbl_gpe_fadt_blocks[0] = NULL;
        acpi_gbl_gpe_fadt_blocks[1] = NULL;
@@ -784,25 +684,15 @@ void acpi_ut_init_globals(void)
        acpi_gbl_exception_handler = NULL;
        acpi_gbl_init_handler = NULL;
 
-       /* Global "typed" ACPI table pointers */
-
-       acpi_gbl_RSDP = NULL;
-       acpi_gbl_XSDT = NULL;
-       acpi_gbl_FACS = NULL;
-       acpi_gbl_FADT = NULL;
-       acpi_gbl_DSDT = NULL;
-
        /* Global Lock support */
 
        acpi_gbl_global_lock_semaphore = NULL;
+       acpi_gbl_global_lock_mutex = NULL;
        acpi_gbl_global_lock_acquired = FALSE;
-       acpi_gbl_global_lock_thread_count = 0;
        acpi_gbl_global_lock_handle = 0;
 
        /* Miscellaneous variables */
 
-       acpi_gbl_table_flags = ACPI_PHYSICAL_POINTER;
-       acpi_gbl_rsdp_original_location = 0;
        acpi_gbl_cm_single_step = FALSE;
        acpi_gbl_db_terminate_threads = FALSE;
        acpi_gbl_shutdown = FALSE;
@@ -837,8 +727,13 @@ void acpi_ut_init_globals(void)
        acpi_gbl_lowest_stack_pointer = ACPI_SIZE_MAX;
 #endif
 
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+       acpi_gbl_display_final_mem_stats = FALSE;
+#endif
+
        return_VOID;
 }
 
 ACPI_EXPORT_SYMBOL(acpi_dbg_level)
 ACPI_EXPORT_SYMBOL(acpi_dbg_layer)
+ACPI_EXPORT_SYMBOL(acpi_gpe_count)
index ff76055..ad3c0d0 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include <acpi/acpi.h>
 #include <acpi/acnamesp.h>
 #include <acpi/acevents.h>
+#include <acpi/actables.h>
 
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utinit")
 
 /* Local prototypes */
-static void
-acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset);
-
 static void acpi_ut_terminate(void);
 
-/*******************************************************************************
- *
- * FUNCTION:    acpi_ut_fadt_register_error
- *
- * PARAMETERS:  register_name           - Pointer to string identifying register
- *              Value                   - Actual register contents value
- *              Offset                  - Byte offset in the FADT
- *
- * RETURN:      AE_BAD_VALUE
- *
- * DESCRIPTION: Display failure message
- *
- ******************************************************************************/
-
-static void
-acpi_ut_fadt_register_error(char *register_name, u32 value, u8 offset)
-{
-
-       ACPI_WARNING((AE_INFO,
-                     "Invalid FADT value %s=%X at offset %X FADT=%p",
-                     register_name, value, offset, acpi_gbl_FADT));
-}
-
-/******************************************************************************
- *
- * FUNCTION:    acpi_ut_validate_fadt
- *
- * PARAMETERS:  None
- *
- * RETURN:      Status
- *
- * DESCRIPTION: Validate various ACPI registers in the FADT
- *
- ******************************************************************************/
-
-acpi_status acpi_ut_validate_fadt(void)
-{
-
-       /*
-        * Verify Fixed ACPI Description Table fields,
-        * but don't abort on any problems, just display error
-        */
-       if (acpi_gbl_FADT->pm1_evt_len < 4) {
-               acpi_ut_fadt_register_error("PM1_EVT_LEN",
-                                           (u32) acpi_gbl_FADT->pm1_evt_len,
-                                           ACPI_FADT_OFFSET(pm1_evt_len));
-       }
-
-       if (!acpi_gbl_FADT->pm1_cnt_len) {
-               acpi_ut_fadt_register_error("PM1_CNT_LEN", 0,
-                                           ACPI_FADT_OFFSET(pm1_cnt_len));
-       }
-
-       if (!acpi_gbl_FADT->xpm1a_evt_blk.address) {
-               acpi_ut_fadt_register_error("X_PM1a_EVT_BLK", 0,
-                                           ACPI_FADT_OFFSET(xpm1a_evt_blk.
-                                                            address));
-       }
-
-       if (!acpi_gbl_FADT->xpm1a_cnt_blk.address) {
-               acpi_ut_fadt_register_error("X_PM1a_CNT_BLK", 0,
-                                           ACPI_FADT_OFFSET(xpm1a_cnt_blk.
-                                                            address));
-       }
-
-       if (!acpi_gbl_FADT->xpm_tmr_blk.address) {
-               acpi_ut_fadt_register_error("X_PM_TMR_BLK", 0,
-                                           ACPI_FADT_OFFSET(xpm_tmr_blk.
-                                                            address));
-       }
-
-       if ((acpi_gbl_FADT->xpm2_cnt_blk.address &&
-            !acpi_gbl_FADT->pm2_cnt_len)) {
-               acpi_ut_fadt_register_error("PM2_CNT_LEN",
-                                           (u32) acpi_gbl_FADT->pm2_cnt_len,
-                                           ACPI_FADT_OFFSET(pm2_cnt_len));
-       }
-
-       if (acpi_gbl_FADT->pm_tm_len < 4) {
-               acpi_ut_fadt_register_error("PM_TM_LEN",
-                                           (u32) acpi_gbl_FADT->pm_tm_len,
-                                           ACPI_FADT_OFFSET(pm_tm_len));
-       }
-
-       /* Length of GPE blocks must be a multiple of 2 */
-
-       if (acpi_gbl_FADT->xgpe0_blk.address &&
-           (acpi_gbl_FADT->gpe0_blk_len & 1)) {
-               acpi_ut_fadt_register_error("(x)GPE0_BLK_LEN",
-                                           (u32) acpi_gbl_FADT->gpe0_blk_len,
-                                           ACPI_FADT_OFFSET(gpe0_blk_len));
-       }
-
-       if (acpi_gbl_FADT->xgpe1_blk.address &&
-           (acpi_gbl_FADT->gpe1_blk_len & 1)) {
-               acpi_ut_fadt_register_error("(x)GPE1_BLK_LEN",
-                                           (u32) acpi_gbl_FADT->gpe1_blk_len,
-                                           ACPI_FADT_OFFSET(gpe1_blk_len));
-       }
-
-       return (AE_OK);
-}
-
 /******************************************************************************
  *
  * FUNCTION:    acpi_ut_terminate
@@ -178,7 +73,6 @@ static void acpi_ut_terminate(void)
 
        ACPI_FUNCTION_TRACE(ut_terminate);
 
-       /* Free global tables, etc. */
        /* Free global GPE blocks and related info structures */
 
        gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
@@ -239,6 +133,10 @@ void acpi_ut_subsystem_shutdown(void)
 
        acpi_ns_terminate();
 
+       /* Delete the ACPI tables */
+
+       acpi_tb_terminate();
+
        /* Close the globals */
 
        acpi_ut_terminate();
index 19d74be..0c56a0d 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6d8a821..50133ff 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define _COMPONENT          ACPI_UTILITIES
 ACPI_MODULE_NAME("utmisc")
 
+/*******************************************************************************
+ *
+ * FUNCTION:    acpi_ut_validate_exception
+ *
+ * PARAMETERS:  Status       - The acpi_status code to be formatted
+ *
+ * RETURN:      A string containing the exception text. NULL if exception is
+ *              not valid.
+ *
+ * DESCRIPTION: This function validates and translates an ACPI exception into
+ *              an ASCII string.
+ *
+ ******************************************************************************/
+const char *acpi_ut_validate_exception(acpi_status status)
+{
+       acpi_status sub_status;
+       const char *exception = NULL;
+
+       ACPI_FUNCTION_ENTRY();
+
+       /*
+        * Status is composed of two parts, a "type" and an actual code
+        */
+       sub_status = (status & ~AE_CODE_MASK);
+
+       switch (status & AE_CODE_MASK) {
+       case AE_CODE_ENVIRONMENTAL:
+
+               if (sub_status <= AE_CODE_ENV_MAX) {
+                       exception = acpi_gbl_exception_names_env[sub_status];
+               }
+               break;
+
+       case AE_CODE_PROGRAMMER:
+
+               if (sub_status <= AE_CODE_PGM_MAX) {
+                       exception =
+                           acpi_gbl_exception_names_pgm[sub_status - 1];
+               }
+               break;
+
+       case AE_CODE_ACPI_TABLES:
+
+               if (sub_status <= AE_CODE_TBL_MAX) {
+                       exception =
+                           acpi_gbl_exception_names_tbl[sub_status - 1];
+               }
+               break;
+
+       case AE_CODE_AML:
+
+               if (sub_status <= AE_CODE_AML_MAX) {
+                       exception =
+                           acpi_gbl_exception_names_aml[sub_status - 1];
+               }
+               break;
+
+       case AE_CODE_CONTROL:
+
+               if (sub_status <= AE_CODE_CTRL_MAX) {
+                       exception =
+                           acpi_gbl_exception_names_ctrl[sub_status - 1];
+               }
+               break;
+
+       default:
+               break;
+       }
+
+       return (ACPI_CAST_PTR(const char, exception));
+}
+
 /*******************************************************************************
  *
  * FUNCTION:    acpi_ut_is_aml_table
@@ -62,14 +134,15 @@ ACPI_MODULE_NAME("utmisc")
  *              data tables that do not contain AML code.
  *
  ******************************************************************************/
+
 u8 acpi_ut_is_aml_table(struct acpi_table_header *table)
 {
 
        /* These are the only tables that contain executable AML */
 
-       if (ACPI_COMPARE_NAME(table->signature, DSDT_SIG) ||
-           ACPI_COMPARE_NAME(table->signature, PSDT_SIG) ||
-           ACPI_COMPARE_NAME(table->signature, SSDT_SIG)) {
+       if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_DSDT) ||
+           ACPI_COMPARE_NAME(table->signature, ACPI_SIG_PSDT) ||
+           ACPI_COMPARE_NAME(table->signature, ACPI_SIG_SSDT)) {
                return (TRUE);
        }
 
@@ -418,7 +491,7 @@ u32 acpi_ut_dword_byte_swap(u32 value)
 void acpi_ut_set_integer_width(u8 revision)
 {
 
-       if (revision <= 1) {
+       if (revision < 2) {
 
                /* 32-bit case */
 
@@ -582,26 +655,25 @@ u8 acpi_ut_valid_acpi_name(u32 name)
  *
  ******************************************************************************/
 
-acpi_name acpi_ut_repair_name(acpi_name name)
+acpi_name acpi_ut_repair_name(char *name)
 {
-       char *name_ptr = ACPI_CAST_PTR(char, &name);
-       char new_name[ACPI_NAME_SIZE];
        acpi_native_uint i;
+       char new_name[ACPI_NAME_SIZE];
 
        for (i = 0; i < ACPI_NAME_SIZE; i++) {
-               new_name[i] = name_ptr[i];
+               new_name[i] = name[i];
 
                /*
                 * Replace a bad character with something printable, yet technically
                 * still invalid. This prevents any collisions with existing "good"
                 * names in the namespace.
                 */
-               if (!acpi_ut_valid_acpi_char(name_ptr[i], i)) {
+               if (!acpi_ut_valid_acpi_char(name[i], i)) {
                        new_name[i] = '*';
                }
        }
 
-       return (*ACPI_CAST_PTR(u32, new_name));
+       return (*(u32 *) new_name);
 }
 
 /*******************************************************************************
@@ -996,9 +1068,13 @@ acpi_ut_info(char *module_name, u32 line_number, char *format, ...)
 {
        va_list args;
 
-       acpi_os_printf("ACPI (%s-%04d): ", module_name, line_number);
+       /*
+        * Removed module_name, line_number, and acpica version, not needed
+        * for info output
+        */
+       acpi_os_printf("ACPI: ");
 
        va_start(args, format);
        acpi_os_vprintf(format, args);
-       acpi_os_printf(" [%X]\n", ACPI_CA_VERSION);
+       acpi_os_printf("\n");
 }
index 180e73c..cbad2ef 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ba7d8ac..4696124 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5a2de92..e8fe1ba 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index eaa13d0..edcaafa 100644 (file)
@@ -5,7 +5,7 @@
  ******************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3538f69..de3276f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -67,6 +67,7 @@ acpi_status acpi_initialize_subsystem(void)
 
        ACPI_FUNCTION_TRACE(acpi_initialize_subsystem);
 
+       acpi_gbl_startup_flags = ACPI_SUBSYSTEM_INITIALIZE;
        ACPI_DEBUG_EXEC(acpi_ut_init_stack_ptr_trace());
 
        /* Initialize the OS-Dependent layer */
@@ -127,20 +128,6 @@ acpi_status acpi_enable_subsystem(u32 flags)
 
        ACPI_FUNCTION_TRACE(acpi_enable_subsystem);
 
-       /*
-        * We must initialize the hardware before we can enable ACPI.
-        * The values from the FADT are validated here.
-        */
-       if (!(flags & ACPI_NO_HARDWARE_INIT)) {
-               ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
-                                 "[Init] Initializing ACPI hardware\n"));
-
-               status = acpi_hw_initialize();
-               if (ACPI_FAILURE(status)) {
-                       return_ACPI_STATUS(status);
-               }
-       }
-
        /* Enable ACPI mode */
 
        if (!(flags & ACPI_NO_ACPI_ENABLE)) {
@@ -398,7 +385,6 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
 {
        struct acpi_system_info *info_ptr;
        acpi_status status;
-       u32 i;
 
        ACPI_FUNCTION_TRACE(acpi_get_system_info);
 
@@ -431,9 +417,7 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
 
        /* Timer resolution - 24 or 32 bits  */
 
-       if (!acpi_gbl_FADT) {
-               info_ptr->timer_resolution = 0;
-       } else if (acpi_gbl_FADT->tmr_val_ext == 0) {
+       if (acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER) {
                info_ptr->timer_resolution = 24;
        } else {
                info_ptr->timer_resolution = 32;
@@ -449,13 +433,6 @@ acpi_status acpi_get_system_info(struct acpi_buffer * out_buffer)
        info_ptr->debug_layer = acpi_dbg_layer;
        info_ptr->debug_level = acpi_dbg_level;
 
-       /* Current status of the ACPI tables, per table type */
-
-       info_ptr->num_table_types = ACPI_TABLE_ID_MAX + 1;
-       for (i = 0; i < (ACPI_TABLE_ID_MAX + 1); i++) {
-               info_ptr->table_info[i].count = acpi_gbl_table_lists[i].count;
-       }
-
        return_ACPI_STATUS(AE_OK);
 }
 
index 3d54680..e0b97ad 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 
+#include <linux/backlight.h>
 #include <asm/uaccess.h>
 
 #include <acpi/acpi_bus.h>
 
 #define ACPI_VIDEO_HEAD_INVALID                (~0u - 1)
 #define ACPI_VIDEO_HEAD_END            (~0u)
+#define MAX_NAME_LEN   20
+
+#define ACPI_VIDEO_DISPLAY_CRT 1
+#define ACPI_VIDEO_DISPLAY_TV  2
+#define ACPI_VIDEO_DISPLAY_DVI 3
+#define ACPI_VIDEO_DISPLAY_LCD 4
 
 #define _COMPONENT             ACPI_VIDEO_COMPONENT
 ACPI_MODULE_NAME("acpi_video")
@@ -66,16 +73,14 @@ MODULE_LICENSE("GPL");
 
 static int acpi_video_bus_add(struct acpi_device *device);
 static int acpi_video_bus_remove(struct acpi_device *device, int type);
-static int acpi_video_bus_match(struct acpi_device *device,
-                               struct acpi_driver *driver);
 
 static struct acpi_driver acpi_video_bus = {
        .name = ACPI_VIDEO_DRIVER_NAME,
        .class = ACPI_VIDEO_CLASS,
+       .ids = ACPI_VIDEO_HID,
        .ops = {
                .add = acpi_video_bus_add,
                .remove = acpi_video_bus_remove,
-               .match = acpi_video_bus_match,
                },
 };
 
@@ -133,20 +138,21 @@ struct acpi_video_device_flags {
        u8 crt:1;
        u8 lcd:1;
        u8 tvout:1;
+       u8 dvi:1;
        u8 bios:1;
        u8 unknown:1;
-       u8 reserved:3;
+       u8 reserved:2;
 };
 
 struct acpi_video_device_cap {
        u8 _ADR:1;              /*Return the unique ID */
        u8 _BCL:1;              /*Query list of brightness control levels supported */
        u8 _BCM:1;              /*Set the brightness level */
+       u8 _BQC:1;              /* Get current brightness level */
        u8 _DDC:1;              /*Return the EDID for this device */
        u8 _DCS:1;              /*Return status of output device */
        u8 _DGS:1;              /*Query graphics state */
        u8 _DSS:1;              /*Device state set */
-       u8 _reserved:1;
 };
 
 struct acpi_video_device_brightness {
@@ -163,6 +169,8 @@ struct acpi_video_device {
        struct acpi_video_bus *video;
        struct acpi_device *dev;
        struct acpi_video_device_brightness *brightness;
+       struct backlight_device *backlight;
+       struct backlight_properties *data;
 };
 
 /* bus */
@@ -257,11 +265,35 @@ static void acpi_video_device_bind(struct acpi_video_bus *video,
                                   struct acpi_video_device *device);
 static int acpi_video_device_enumerate(struct acpi_video_bus *video);
 static int acpi_video_switch_output(struct acpi_video_bus *video, int event);
+static int acpi_video_device_lcd_set_level(struct acpi_video_device *device,
+                       int level);
+static int acpi_video_device_lcd_get_level_current(
+                       struct acpi_video_device *device,
+                       unsigned long *level);
 static int acpi_video_get_next_level(struct acpi_video_device *device,
                                     u32 level_current, u32 event);
 static void acpi_video_switch_brightness(struct acpi_video_device *device,
                                         int event);
 
+/*backlight device sysfs support*/
+static int acpi_video_get_brightness(struct backlight_device *bd)
+{
+       unsigned long cur_level;
+       struct acpi_video_device *vd =
+               (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+       acpi_video_device_lcd_get_level_current(vd, &cur_level);
+       return (int) cur_level;
+}
+
+static int acpi_video_set_brightness(struct backlight_device *bd)
+{
+       int request_level = bd->props->brightness;
+       struct acpi_video_device *vd =
+               (struct acpi_video_device *)class_get_devdata(&bd->class_dev);
+       acpi_video_device_lcd_set_level(vd, request_level);
+       return 0;
+}
+
 /* --------------------------------------------------------------------------
                                Video Management
    -------------------------------------------------------------------------- */
@@ -499,6 +531,7 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
        acpi_integer status;
        acpi_handle h_dummy1;
        int i;
+       u32 max_level = 0;
        union acpi_object *obj = NULL;
        struct acpi_video_device_brightness *br = NULL;
 
@@ -514,6 +547,8 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
        if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_BCM", &h_dummy1))) {
                device->cap._BCM = 1;
        }
+       if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle,"_BQC",&h_dummy1)))
+               device->cap._BQC = 1;
        if (ACPI_SUCCESS(acpi_get_handle(device->dev->handle, "_DDC", &h_dummy1))) {
                device->cap._DDC = 1;
        }
@@ -550,6 +585,8 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
                                        continue;
                                }
                                br->levels[count] = (u32) o->integer.value;
+                               if (br->levels[count] > max_level)
+                                       max_level = br->levels[count];
                                count++;
                        }
                      out:
@@ -568,6 +605,37 @@ static void acpi_video_device_find_cap(struct acpi_video_device *device)
 
        kfree(obj);
 
+       if (device->cap._BCL && device->cap._BCM && device->cap._BQC){
+               unsigned long tmp;
+               static int count = 0;
+               char *name;
+               struct backlight_properties *acpi_video_data;
+
+               name = kzalloc(MAX_NAME_LEN, GFP_KERNEL);
+               if (!name)
+                       return;
+
+               acpi_video_data = kzalloc(
+                       sizeof(struct backlight_properties),
+                       GFP_KERNEL);
+               if (!acpi_video_data){
+                       kfree(name);
+                       return;
+               }
+               acpi_video_data->owner = THIS_MODULE;
+               acpi_video_data->get_brightness =
+                       acpi_video_get_brightness;
+               acpi_video_data->update_status =
+                       acpi_video_set_brightness;
+               sprintf(name, "acpi_video%d", count++);
+               device->data = acpi_video_data;
+               acpi_video_data->max_brightness = max_level;
+               acpi_video_device_lcd_get_level_current(device, &tmp);
+               acpi_video_data->brightness = (int)tmp;
+               device->backlight = backlight_device_register(name,
+                       NULL, device, acpi_video_data);
+               kfree(name);
+       }
        return;
 }
 
@@ -668,6 +736,8 @@ static int acpi_video_device_info_seq_show(struct seq_file *seq, void *offset)
                seq_printf(seq, "LCD\n");
        else if (dev->flags.tvout)
                seq_printf(seq, "TVOUT\n");
+       else if (dev->flags.dvi)
+               seq_printf(seq, "DVI\n");
        else
                seq_printf(seq, "UNKNOWN\n");
 
@@ -1242,6 +1312,16 @@ static int acpi_video_bus_remove_fs(struct acpi_device *device)
    -------------------------------------------------------------------------- */
 
 /* device interface */
+static struct acpi_video_device_attrib*
+acpi_video_get_device_attr(struct acpi_video_bus *video, unsigned long device_id)
+{
+       int count;
+
+       for(count = 0; count < video->attached_count; count++)
+               if((video->attached_array[count].value.int_val & 0xffff) == device_id)
+                       return &(video->attached_array[count].value.attrib);
+       return NULL;
+}
 
 static int
 acpi_video_bus_get_one_device(struct acpi_device *device,
@@ -1250,7 +1330,7 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
        unsigned long device_id;
        int status;
        struct acpi_video_device *data;
-
+       struct acpi_video_device_attrib* attribute;
 
        if (!device || !video)
                return -EINVAL;
@@ -1271,20 +1351,30 @@ acpi_video_bus_get_one_device(struct acpi_device *device,
                data->video = video;
                data->dev = device;
 
-               switch (device_id & 0xffff) {
-               case 0x0100:
-                       data->flags.crt = 1;
-                       break;
-               case 0x0400:
-                       data->flags.lcd = 1;
-                       break;
-               case 0x0200:
-                       data->flags.tvout = 1;
-                       break;
-               default:
+               attribute = acpi_video_get_device_attr(video, device_id);
+
+               if((attribute != NULL) && attribute->device_id_scheme) {
+                       switch (attribute->display_type) {
+                       case ACPI_VIDEO_DISPLAY_CRT:
+                               data->flags.crt = 1;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_TV:
+                               data->flags.tvout = 1;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_DVI:
+                               data->flags.dvi = 1;
+                               break;
+                       case ACPI_VIDEO_DISPLAY_LCD:
+                               data->flags.lcd = 1;
+                               break;
+                       default:
+                               data->flags.unknown = 1;
+                               break;
+                       }
+                       if(attribute->bios_can_detect)
+                               data->flags.bios = 1;
+               } else
                        data->flags.unknown = 1;
-                       break;
-               }
 
                acpi_video_device_bind(video, data);
                acpi_video_device_find_cap(data);
@@ -1588,7 +1678,10 @@ static int acpi_video_bus_put_one_device(struct acpi_video_device *device)
        status = acpi_remove_notify_handler(device->dev->handle,
                                            ACPI_DEVICE_NOTIFY,
                                            acpi_video_device_notify);
-
+       if (device->backlight){
+               backlight_device_unregister(device->backlight);
+               kfree(device->data);
+       }
        return 0;
 }
 
@@ -1790,39 +1883,6 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type)
        return 0;
 }
 
-static int
-acpi_video_bus_match(struct acpi_device *device, struct acpi_driver *driver)
-{
-       acpi_handle h_dummy1;
-       acpi_handle h_dummy2;
-       acpi_handle h_dummy3;
-
-
-       if (!device || !driver)
-               return -EINVAL;
-
-       /* Since there is no HID, CID for ACPI Video drivers, we have
-        * to check well known required nodes for each feature we support.
-        */
-
-       /* Does this device able to support video switching ? */
-       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOD", &h_dummy1)) &&
-           ACPI_SUCCESS(acpi_get_handle(device->handle, "_DOS", &h_dummy2)))
-               return 0;
-
-       /* Does this device able to retrieve a video ROM ? */
-       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_ROM", &h_dummy1)))
-               return 0;
-
-       /* Does this device able to configure which video head to be POSTed ? */
-       if (ACPI_SUCCESS(acpi_get_handle(device->handle, "_VPO", &h_dummy1)) &&
-           ACPI_SUCCESS(acpi_get_handle(device->handle, "_GPD", &h_dummy2)) &&
-           ACPI_SUCCESS(acpi_get_handle(device->handle, "_SPD", &h_dummy3)))
-               return 0;
-
-       return -ENODEV;
-}
-
 static int __init acpi_video_init(void)
 {
        int result = 0;
index 8bf2ca2..96def1d 100644 (file)
@@ -364,7 +364,7 @@ char *make_class_name(const char *name, struct kobject *kobj)
 
        class_name = kmalloc(size, GFP_KERNEL);
        if (!class_name)
-               return ERR_PTR(-ENOMEM);
+               return NULL;
 
        strcpy(class_name, name);
        strcat(class_name, ":");
@@ -411,8 +411,11 @@ static int make_deprecated_class_device_links(struct class_device *class_dev)
                return 0;
 
        class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
-       error = sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
-                                 class_name);
+       if (class_name)
+               error = sysfs_create_link(&class_dev->dev->kobj,
+                                         &class_dev->kobj, class_name);
+       else
+               error = -ENOMEM;
        kfree(class_name);
        return error;
 }
@@ -425,7 +428,8 @@ static void remove_deprecated_class_device_links(struct class_device *class_dev)
                return;
 
        class_name = make_class_name(class_dev->class->name, &class_dev->kobj);
-       sysfs_remove_link(&class_dev->dev->kobj, class_name);
+       if (class_name)
+               sysfs_remove_link(&class_dev->dev->kobj, class_name);
        kfree(class_name);
 }
 #else
@@ -863,9 +867,12 @@ int class_device_rename(struct class_device *class_dev, char *new_name)
        if (class_dev->dev) {
                new_class_name = make_class_name(class_dev->class->name,
                                                 &class_dev->kobj);
-               sysfs_create_link(&class_dev->dev->kobj, &class_dev->kobj,
-                                 new_class_name);
-               sysfs_remove_link(&class_dev->dev->kobj, old_class_name);
+               if (new_class_name)
+                       sysfs_create_link(&class_dev->dev->kobj,
+                                         &class_dev->kobj, new_class_name);
+               if (old_class_name)
+                       sysfs_remove_link(&class_dev->dev->kobj,
+                                               old_class_name);
        }
 #endif
        class_device_put(class_dev);
index 67b79a7..e136142 100644 (file)
@@ -95,6 +95,8 @@ static void device_release(struct kobject * kobj)
 
        if (dev->release)
                dev->release(dev);
+       else if (dev->type && dev->type->release)
+               dev->type->release(dev);
        else if (dev->class && dev->class->dev_release)
                dev->class->dev_release(dev);
        else {
@@ -154,25 +156,47 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
                               "MINOR=%u", MINOR(dev->devt));
        }
 
-#ifdef CONFIG_SYSFS_DEPRECATED
-       /* add bus name (same as SUBSYSTEM, deprecated) */
-       if (dev->bus)
-               add_uevent_var(envp, num_envp, &i,
-                              buffer, buffer_size, &length,
-                              "PHYSDEVBUS=%s", dev->bus->name);
-#endif
-
-       /* add driver name (PHYSDEV* values are deprecated)*/
-       if (dev->driver) {
+       if (dev->driver)
                add_uevent_var(envp, num_envp, &i,
                               buffer, buffer_size, &length,
                               "DRIVER=%s", dev->driver->name);
+
 #ifdef CONFIG_SYSFS_DEPRECATED
+       if (dev->class) {
+               struct device *parent = dev->parent;
+
+               /* find first bus device in parent chain */
+               while (parent && !parent->bus)
+                       parent = parent->parent;
+               if (parent && parent->bus) {
+                       const char *path;
+
+                       path = kobject_get_path(&parent->kobj, GFP_KERNEL);
+                       add_uevent_var(envp, num_envp, &i,
+                                      buffer, buffer_size, &length,
+                                      "PHYSDEVPATH=%s", path);
+                       kfree(path);
+
+                       add_uevent_var(envp, num_envp, &i,
+                                      buffer, buffer_size, &length,
+                                      "PHYSDEVBUS=%s", parent->bus->name);
+
+                       if (parent->driver)
+                               add_uevent_var(envp, num_envp, &i,
+                                              buffer, buffer_size, &length,
+                                              "PHYSDEVDRIVER=%s", parent->driver->name);
+               }
+       } else if (dev->bus) {
                add_uevent_var(envp, num_envp, &i,
                               buffer, buffer_size, &length,
-                              "PHYSDEVDRIVER=%s", dev->driver->name);
-#endif
+                              "PHYSDEVBUS=%s", dev->bus->name);
+
+               if (dev->driver)
+                       add_uevent_var(envp, num_envp, &i,
+                                      buffer, buffer_size, &length,
+                                      "PHYSDEVDRIVER=%s", dev->driver->name);
        }
+#endif
 
        /* terminate, set to next free slot, shrink available space */
        envp[i] = NULL;
@@ -184,19 +208,25 @@ static int dev_uevent(struct kset *kset, struct kobject *kobj, char **envp,
        if (dev->bus && dev->bus->uevent) {
                /* have the bus specific function add its stuff */
                retval = dev->bus->uevent(dev, envp, num_envp, buffer, buffer_size);
-                       if (retval) {
-                       pr_debug ("%s - uevent() returned %d\n",
+               if (retval)
+                       pr_debug ("%s: bus uevent() returned %d\n",
                                  __FUNCTION__, retval);
-               }
        }
 
        if (dev->class && dev->class->dev_uevent) {
                /* have the class specific function add its stuff */
                retval = dev->class->dev_uevent(dev, envp, num_envp, buffer, buffer_size);
-                       if (retval) {
-                               pr_debug("%s - dev_uevent() returned %d\n",
-                                        __FUNCTION__, retval);
-               }
+               if (retval)
+                       pr_debug("%s: class uevent() returned %d\n",
+                                __FUNCTION__, retval);
+       }
+
+       if (dev->type && dev->type->uevent) {
+               /* have the device type specific fuction add its stuff */
+               retval = dev->type->uevent(dev, envp, num_envp, buffer, buffer_size);
+               if (retval)
+                       pr_debug("%s: dev_type uevent() returned %d\n",
+                                __FUNCTION__, retval);
        }
 
        return retval;
@@ -247,37 +277,50 @@ static void device_remove_groups(struct device *dev)
 static int device_add_attrs(struct device *dev)
 {
        struct class *class = dev->class;
+       struct device_type *type = dev->type;
        int error = 0;
        int i;
 
-       if (!class)
-               return 0;
-
-       if (class->dev_attrs) {
+       if (class && class->dev_attrs) {
                for (i = 0; attr_name(class->dev_attrs[i]); i++) {
                        error = device_create_file(dev, &class->dev_attrs[i]);
                        if (error)
                                break;
                }
+               if (error)
+                       while (--i >= 0)
+                               device_remove_file(dev, &class->dev_attrs[i]);
        }
-       if (error)
-               while (--i >= 0)
-                       device_remove_file(dev, &class->dev_attrs[i]);
+
+       if (type && type->attrs) {
+               for (i = 0; attr_name(type->attrs[i]); i++) {
+                       error = device_create_file(dev, &type->attrs[i]);
+                       if (error)
+                               break;
+               }
+               if (error)
+                       while (--i >= 0)
+                               device_remove_file(dev, &type->attrs[i]);
+       }
+
        return error;
 }
 
 static void device_remove_attrs(struct device *dev)
 {
        struct class *class = dev->class;
+       struct device_type *type = dev->type;
        int i;
 
-       if (!class)
-               return;
-
-       if (class->dev_attrs) {
+       if (class && class->dev_attrs) {
                for (i = 0; attr_name(class->dev_attrs[i]); i++)
                        device_remove_file(dev, &class->dev_attrs[i]);
        }
+
+       if (type && type->attrs) {
+               for (i = 0; attr_name(type->attrs[i]); i++)
+                       device_remove_file(dev, &type->attrs[i]);
+       }
 }
 
 
@@ -390,22 +433,23 @@ void device_initialize(struct device *dev)
 }
 
 #ifdef CONFIG_SYSFS_DEPRECATED
-static int setup_parent(struct device *dev, struct device *parent)
+static struct kobject * get_device_parent(struct device *dev,
+                                         struct device *parent)
 {
        /* Set the parent to the class, not the parent device */
        /* this keeps sysfs from having a symlink to make old udevs happy */
        if (dev->class)
-               dev->kobj.parent = &dev->class->subsys.kset.kobj;
+               return &dev->class->subsys.kset.kobj;
        else if (parent)
-               dev->kobj.parent = &parent->kobj;
+               return &parent->kobj;
 
-       return 0;
+       return NULL;
 }
 #else
-static int virtual_device_parent(struct device *dev)
+static struct kobject * virtual_device_parent(struct device *dev)
 {
        if (!dev->class)
-               return -ENODEV;
+               return ERR_PTR(-ENODEV);
 
        if (!dev->class->virtual_dir) {
                static struct kobject *virtual_dir = NULL;
@@ -415,25 +459,31 @@ static int virtual_device_parent(struct device *dev)
                dev->class->virtual_dir = kobject_add_dir(virtual_dir, dev->class->name);
        }
 
-       dev->kobj.parent = dev->class->virtual_dir;
-       return 0;
+       return dev->class->virtual_dir;
 }
 
-static int setup_parent(struct device *dev, struct device *parent)
+static struct kobject * get_device_parent(struct device *dev,
+                                         struct device *parent)
 {
-       int error;
-
        /* if this is a class device, and has no parent, create one */
        if ((dev->class) && (parent == NULL)) {
-               error = virtual_device_parent(dev);
-               if (error)
-                       return error;
+               return virtual_device_parent(dev);
        } else if (parent)
-               dev->kobj.parent = &parent->kobj;
+               return &parent->kobj;
+       return NULL;
+}
 
+#endif
+static int setup_parent(struct device *dev, struct device *parent)
+{
+       struct kobject *kobj;
+       kobj = get_device_parent(dev, parent);
+       if (IS_ERR(kobj))
+               return PTR_ERR(kobj);
+       if (kobj)
+               dev->kobj.parent = kobj;
        return 0;
 }
-#endif
 
 /**
  *     device_add - add device to device hierarchy.
@@ -520,9 +570,13 @@ int device_add(struct device *dev)
                                          &dev->kobj, dev->bus_id);
 #ifdef CONFIG_SYSFS_DEPRECATED
                if (parent) {
-                       sysfs_create_link(&dev->kobj, &dev->parent->kobj, "device");
-                       class_name = make_class_name(dev->class->name, &dev->kobj);
-                       sysfs_create_link(&dev->parent->kobj, &dev->kobj, class_name);
+                       sysfs_create_link(&dev->kobj, &dev->parent->kobj,
+                                                       "device");
+                       class_name = make_class_name(dev->class->name,
+                                                       &dev->kobj);
+                       if (class_name)
+                               sysfs_create_link(&dev->parent->kobj,
+                                                 &dev->kobj, class_name);
                }
 #endif
        }
@@ -535,7 +589,8 @@ int device_add(struct device *dev)
                goto PMError;
        if ((error = bus_add_device(dev)))
                goto BusError;
-       kobject_uevent(&dev->kobj, KOBJ_ADD);
+       if (!dev->uevent_suppress)
+               kobject_uevent(&dev->kobj, KOBJ_ADD);
        if ((error = bus_attach_device(dev)))
                goto AttachError;
        if (parent)
@@ -665,7 +720,9 @@ void device_del(struct device * dev)
                if (parent) {
                        char *class_name = make_class_name(dev->class->name,
                                                           &dev->kobj);
-                       sysfs_remove_link(&dev->parent->kobj, class_name);
+                       if (class_name)
+                               sysfs_remove_link(&dev->parent->kobj,
+                                                 class_name);
                        kfree(class_name);
                        sysfs_remove_link(&dev->kobj, "device");
                }
@@ -968,20 +1025,25 @@ static int device_move_class_links(struct device *dev,
 
        class_name = make_class_name(dev->class->name, &dev->kobj);
        if (!class_name) {
-               error = PTR_ERR(class_name);
-               class_name = NULL;
+               error = -ENOMEM;
                goto out;
        }
        if (old_parent) {
                sysfs_remove_link(&dev->kobj, "device");
                sysfs_remove_link(&old_parent->kobj, class_name);
        }
-       error = sysfs_create_link(&dev->kobj, &new_parent->kobj, "device");
-       if (error)
-               goto out;
-       error = sysfs_create_link(&new_parent->kobj, &dev->kobj, class_name);
-       if (error)
-               sysfs_remove_link(&dev->kobj, "device");
+       if (new_parent) {
+               error = sysfs_create_link(&dev->kobj, &new_parent->kobj,
+                                         "device");
+               if (error)
+                       goto out;
+               error = sysfs_create_link(&new_parent->kobj, &dev->kobj,
+                                         class_name);
+               if (error)
+                       sysfs_remove_link(&dev->kobj, "device");
+       }
+       else
+               error = 0;
 out:
        kfree(class_name);
        return error;
@@ -993,29 +1055,28 @@ out:
 /**
  * device_move - moves a device to a new parent
  * @dev: the pointer to the struct device to be moved
- * @new_parent: the new parent of the device
+ * @new_parent: the new parent of the device (can by NULL)
  */
 int device_move(struct device *dev, struct device *new_parent)
 {
        int error;
        struct device *old_parent;
+       struct kobject *new_parent_kobj;
 
        dev = get_device(dev);
        if (!dev)
                return -EINVAL;
 
-       if (!device_is_registered(dev)) {
-               error = -EINVAL;
-               goto out;
-       }
        new_parent = get_device(new_parent);
-       if (!new_parent) {
-               error = -EINVAL;
+       new_parent_kobj = get_device_parent (dev, new_parent);
+       if (IS_ERR(new_parent_kobj)) {
+               error = PTR_ERR(new_parent_kobj);
+               put_device(new_parent);
                goto out;
        }
        pr_debug("DEVICE: moving '%s' to '%s'\n", dev->bus_id,
-               new_parent->bus_id);
-       error = kobject_move(&dev->kobj, &new_parent->kobj);
+                new_parent ? new_parent->bus_id : "<NULL>");
+       error = kobject_move(&dev->kobj, new_parent_kobj);
        if (error) {
                put_device(new_parent);
                goto out;
@@ -1024,7 +1085,8 @@ int device_move(struct device *dev, struct device *new_parent)
        dev->parent = new_parent;
        if (old_parent)
                klist_remove(&dev->knode_parent);
-       klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
+       if (new_parent)
+               klist_add_tail(&dev->knode_parent, &new_parent->klist_children);
        if (!dev->class)
                goto out_put;
        error = device_move_class_links(dev, old_parent, new_parent);
@@ -1032,7 +1094,8 @@ int device_move(struct device *dev, struct device *new_parent)
                /* We ignore errors on cleanup since we're hosed anyway... */
                device_move_class_links(dev, new_parent, old_parent);
                if (!kobject_move(&dev->kobj, &old_parent->kobj)) {
-                       klist_remove(&dev->knode_parent);
+                       if (new_parent)
+                               klist_remove(&dev->knode_parent);
                        if (old_parent)
                                klist_add_tail(&dev->knode_parent,
                                               &old_parent->klist_children);
index 510e788..b5bf243 100644 (file)
@@ -86,8 +86,12 @@ static void driver_sysfs_remove(struct device *dev)
  */
 int device_bind_driver(struct device *dev)
 {
-       driver_bound(dev);
-       return driver_sysfs_add(dev);
+       int ret;
+
+       ret = driver_sysfs_add(dev);
+       if (!ret)
+               driver_bound(dev);
+       return ret;
 }
 
 struct stupid_thread_structure {
@@ -136,18 +140,17 @@ probe_failed:
        driver_sysfs_remove(dev);
        dev->driver = NULL;
 
-       if (ret == -ENODEV || ret == -ENXIO) {
-               /* Driver matched, but didn't support device
-                * or device not found.
-                * Not an error; keep going.
-                */
-               ret = 0;
-       } else {
+       if (ret != -ENODEV && ret != -ENXIO) {
                /* driver matched but the probe failed */
                printk(KERN_WARNING
                       "%s: probe of %s failed with error %d\n",
                       drv->name, dev->bus_id, ret);
        }
+       /*
+        * Ignore errors returned by ->probe so that the next driver can try
+        * its luck.
+        */
+       ret = 0;
 done:
        kfree(data);
        atomic_dec(&probe_count);
index 64558f4..c0a979a 100644 (file)
@@ -35,7 +35,7 @@ enum {
        FW_STATUS_READY_NOHOTPLUG,
 };
 
-static int loading_timeout = 10;       /* In seconds */
+static int loading_timeout = 60;       /* In seconds */
 
 /* fw_lock could be moved to 'struct firmware_priv' but since it is just
  * guarding for corner cases a global lock should be OK */
index f9c903b..30480f6 100644 (file)
@@ -611,8 +611,15 @@ EXPORT_SYMBOL_GPL(platform_bus_type);
 
 int __init platform_bus_init(void)
 {
-       device_register(&platform_bus);
-       return bus_register(&platform_bus_type);
+       int error;
+
+       error = device_register(&platform_bus);
+       if (error)
+               return error;
+       error =  bus_register(&platform_bus_type);
+       if (error)
+               device_unregister(&platform_bus);
+       return error;
 }
 
 #ifndef ARCH_HAS_DMA_GET_REQUIRED_MASK
index 6dcdceb..85d99e2 100644 (file)
@@ -532,11 +532,13 @@ typedef struct drm_mm_node {
        int free;
        unsigned long start;
        unsigned long size;
+       struct drm_mm *mm;
        void *private;
 } drm_mm_node_t;
 
 typedef struct drm_mm {
-       drm_mm_node_t root_node;
+       struct list_head fl_entry;
+       struct list_head ml_entry;
 } drm_mm_t;
 
 /**
@@ -843,9 +845,6 @@ extern void drm_mem_init(void);
 extern int drm_mem_info(char *buf, char **start, off_t offset,
                        int request, int *eof, void *data);
 extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area);
-extern void *drm_ioremap(unsigned long offset, unsigned long size,
-                        drm_device_t * dev);
-extern void drm_ioremapfree(void *pt, unsigned long size, drm_device_t * dev);
 
 extern DRM_AGP_MEM *drm_alloc_agp(drm_device_t * dev, int pages, u32 type);
 extern int drm_free_agp(DRM_AGP_MEM * handle, int pages);
@@ -1053,33 +1052,18 @@ extern void drm_sysfs_device_remove(struct class_device *class_dev);
 extern drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
                                       unsigned long size,
                                       unsigned alignment);
-extern void drm_mm_put_block(drm_mm_t *mm, drm_mm_node_t *cur);
+void drm_mm_put_block(drm_mm_node_t * cur);
 extern drm_mm_node_t *drm_mm_search_free(const drm_mm_t *mm, unsigned long size,
                                         unsigned alignment, int best_match);
 extern int drm_mm_init(drm_mm_t *mm, unsigned long start, unsigned long size);
 extern void drm_mm_takedown(drm_mm_t *mm);
+extern int drm_mm_clean(drm_mm_t *mm);
+extern unsigned long drm_mm_tail_space(drm_mm_t *mm);
+extern int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size);
+extern int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size);
 
-/* Inline replacements for DRM_IOREMAP macros */
-static __inline__ void drm_core_ioremap(struct drm_map *map,
-                                       struct drm_device *dev)
-{
-       map->handle = drm_ioremap(map->offset, map->size, dev);
-}
-
-#if 0
-static __inline__ void drm_core_ioremap_nocache(struct drm_map *map,
-                                               struct drm_device *dev)
-{
-       map->handle = drm_ioremap_nocache(map->offset, map->size, dev);
-}
-#endif  /*  0  */
-
-static __inline__ void drm_core_ioremapfree(struct drm_map *map,
-                                           struct drm_device *dev)
-{
-       if (map->handle && map->size)
-               drm_ioremapfree(map->handle, map->size, dev);
-}
+extern void drm_core_ioremap(struct drm_map *map, struct drm_device *dev);
+extern void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev);
 
 static __inline__ struct drm_map *drm_core_findmap(struct drm_device *dev,
                                                   unsigned int token)
index 9f65f56..a6828cc 100644 (file)
@@ -79,14 +79,14 @@ static int drm_map_handle(drm_device_t *dev, drm_hash_item_t *hash,
 
        if (!use_hashed_handle) {
                int ret;
-               hash->key = user_token;
+               hash->key = user_token >> PAGE_SHIFT;
                ret = drm_ht_insert_item(&dev->map_hash, hash);
                if (ret != -EINVAL)
                        return ret;
        }
        return drm_ht_just_insert_please(&dev->map_hash, hash,
                                         user_token, 32 - PAGE_SHIFT - 3,
-                                        PAGE_SHIFT, DRM_MAP_HASH_OFFSET);
+                                        0, DRM_MAP_HASH_OFFSET >> PAGE_SHIFT);
 }
 
 /**
@@ -178,11 +178,11 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
                        }
                }
                if (map->type == _DRM_REGISTERS)
-                       map->handle = drm_ioremap(map->offset, map->size, dev);
+                       map->handle = ioremap(map->offset, map->size);
                break;
 
        case _DRM_SHM:
-               map->handle = vmalloc_32(map->size);
+               map->handle = vmalloc_user(map->size);
                DRM_DEBUG("%lu %d %p\n",
                          map->size, drm_order(map->size), map->handle);
                if (!map->handle) {
@@ -238,7 +238,7 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
        list = drm_alloc(sizeof(*list), DRM_MEM_MAPS);
        if (!list) {
                if (map->type == _DRM_REGISTERS)
-                       drm_ioremapfree(map->handle, map->size, dev);
+                       iounmap(map->handle);
                drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                return -EINVAL;
        }
@@ -255,14 +255,14 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
        ret = drm_map_handle(dev, &list->hash, user_token, 0);
        if (ret) {
                if (map->type == _DRM_REGISTERS)
-                       drm_ioremapfree(map->handle, map->size, dev);
+                       iounmap(map->handle);
                drm_free(map, sizeof(*map), DRM_MEM_MAPS);
                drm_free(list, sizeof(*list), DRM_MEM_MAPS);
                mutex_unlock(&dev->struct_mutex);
                return ret;
        }
 
-       list->user_token = list->hash.key;
+       list->user_token = list->hash.key << PAGE_SHIFT;
        mutex_unlock(&dev->struct_mutex);
 
        *maplist = list;
@@ -347,7 +347,8 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
 
                if (r_list->map == map) {
                        list_del(list);
-                       drm_ht_remove_key(&dev->map_hash, r_list->user_token);
+                       drm_ht_remove_key(&dev->map_hash,
+                                         r_list->user_token >> PAGE_SHIFT);
                        drm_free(list, sizeof(*list), DRM_MEM_MAPS);
                        break;
                }
@@ -362,7 +363,7 @@ int drm_rmmap_locked(drm_device_t *dev, drm_local_map_t *map)
 
        switch (map->type) {
        case _DRM_REGISTERS:
-               drm_ioremapfree(map->handle, map->size, dev);
+               iounmap(map->handle);
                /* FALLTHROUGH */
        case _DRM_FRAME_BUFFER:
                if (drm_core_has_MTRR(dev) && map->mtrr >= 0) {
index 5681cae..92a8670 100644 (file)
@@ -79,28 +79,6 @@ void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
 }
 
 #if __OS_HAS_AGP
-/*
- * Find the drm_map that covers the range [offset, offset+size).
- */
-static drm_map_t *drm_lookup_map(unsigned long offset,
-                                unsigned long size, drm_device_t * dev)
-{
-       struct list_head *list;
-       drm_map_list_t *r_list;
-       drm_map_t *map;
-
-       list_for_each(list, &dev->maplist->head) {
-               r_list = (drm_map_list_t *) list;
-               map = r_list->map;
-               if (!map)
-                       continue;
-               if (map->offset <= offset
-                   && (offset + size) <= (map->offset + map->size))
-                       return map;
-       }
-       return NULL;
-}
-
 static void *agp_remap(unsigned long offset, unsigned long size,
                       drm_device_t * dev)
 {
@@ -169,13 +147,6 @@ int drm_unbind_agp(DRM_AGP_MEM * handle)
 }
 
 #else  /*  __OS_HAS_AGP  */
-
-static inline drm_map_t *drm_lookup_map(unsigned long offset,
-                                       unsigned long size, drm_device_t * dev)
-{
-       return NULL;
-}
-
 static inline void *agp_remap(unsigned long offset, unsigned long size,
                              drm_device_t * dev)
 {
@@ -184,57 +155,28 @@ static inline void *agp_remap(unsigned long offset, unsigned long size,
 
 #endif                         /* agp */
 
-void *drm_ioremap(unsigned long offset, unsigned long size,
-                               drm_device_t * dev)
-{
-       if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
-               drm_map_t *map = drm_lookup_map(offset, size, dev);
-
-               if (map && map->type == _DRM_AGP)
-                       return agp_remap(offset, size, dev);
-       }
-       return ioremap(offset, size);
-}
-EXPORT_SYMBOL(drm_ioremap);
+#endif                         /* debug_memory */
 
-#if 0
-void *drm_ioremap_nocache(unsigned long offset,
-                                       unsigned long size, drm_device_t * dev)
+void drm_core_ioremap(struct drm_map *map, struct drm_device *dev)
 {
-       if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture) {
-               drm_map_t *map = drm_lookup_map(offset, size, dev);
-
-               if (map && map->type == _DRM_AGP)
-                       return agp_remap(offset, size, dev);
-       }
-       return ioremap_nocache(offset, size);
+       if (drm_core_has_AGP(dev) &&
+           dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+               map->handle = agp_remap(map->offset, map->size, dev);
+       else
+               map->handle = ioremap(map->offset, map->size);
 }
-#endif  /*  0  */
+EXPORT_SYMBOL(drm_core_ioremap);
 
-void drm_ioremapfree(void *pt, unsigned long size,
-                                  drm_device_t * dev)
+void drm_core_ioremapfree(struct drm_map *map, struct drm_device *dev)
 {
-       /*
-        * This is a bit ugly.  It would be much cleaner if the DRM API would use separate
-        * routines for handling mappings in the AGP space.  Hopefully this can be done in
-        * a future revision of the interface...
-        */
-       if (drm_core_has_AGP(dev) && dev->agp && dev->agp->cant_use_aperture
-           && ((unsigned long)pt >= VMALLOC_START
-               && (unsigned long)pt < VMALLOC_END)) {
-               unsigned long offset;
-               drm_map_t *map;
-
-               offset = drm_follow_page(pt) | ((unsigned long)pt & ~PAGE_MASK);
-               map = drm_lookup_map(offset, size, dev);
-               if (map && map->type == _DRM_AGP) {
-                       vunmap(pt);
-                       return;
-               }
-       }
-
-       iounmap(pt);
+       if (!map->handle || !map->size)
+               return;
+
+       if (drm_core_has_AGP(dev) &&
+           dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+               vunmap(map->handle);
+       else
+               iounmap(map->handle);
 }
-EXPORT_SYMBOL(drm_ioremapfree);
+EXPORT_SYMBOL(drm_core_ioremapfree);
 
-#endif                         /* debug_memory */
index f1b97af..63e425b 100644 (file)
 # endif
 #endif
 
-static inline unsigned long drm_follow_page(void *vaddr)
-{
-       pgd_t *pgd = pgd_offset_k((unsigned long)vaddr);
-       pud_t *pud = pud_offset(pgd, (unsigned long)vaddr);
-       pmd_t *pmd = pmd_offset(pud, (unsigned long)vaddr);
-       pte_t *ptep = pte_offset_kernel(pmd, (unsigned long)vaddr);
-       return pte_pfn(*ptep) << PAGE_SHIFT;
-}
-
 #else                          /* __OS_HAS_AGP */
 
-static inline unsigned long drm_follow_page(void *vaddr)
-{
-       return 0;
-}
-
 #endif
-
-void *drm_ioremap(unsigned long offset, unsigned long size,
-                               drm_device_t * dev);
-
-void drm_ioremapfree(void *pt, unsigned long size,
-                                  drm_device_t * dev);
index 74581af..6463271 100644 (file)
@@ -205,76 +205,6 @@ void drm_free (void *pt, size_t size, int area) {
        }
 }
 
-void *drm_ioremap (unsigned long offset, unsigned long size,
-                   drm_device_t * dev) {
-       void *pt;
-
-       if (!size) {
-               DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
-                             "Mapping 0 bytes at 0x%08lx\n", offset);
-               return NULL;
-       }
-
-       if (!(pt = drm_ioremap(offset, size, dev))) {
-               spin_lock(&drm_mem_lock);
-               ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
-               spin_unlock(&drm_mem_lock);
-               return NULL;
-       }
-       spin_lock(&drm_mem_lock);
-       ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
-       drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
-       spin_unlock(&drm_mem_lock);
-       return pt;
-}
-
-#if 0
-void *drm_ioremap_nocache (unsigned long offset, unsigned long size,
-                           drm_device_t * dev) {
-       void *pt;
-
-       if (!size) {
-               DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
-                             "Mapping 0 bytes at 0x%08lx\n", offset);
-               return NULL;
-       }
-
-       if (!(pt = drm_ioremap_nocache(offset, size, dev))) {
-               spin_lock(&drm_mem_lock);
-               ++drm_mem_stats[DRM_MEM_MAPPINGS].fail_count;
-               spin_unlock(&drm_mem_lock);
-               return NULL;
-       }
-       spin_lock(&drm_mem_lock);
-       ++drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
-       drm_mem_stats[DRM_MEM_MAPPINGS].bytes_allocated += size;
-       spin_unlock(&drm_mem_lock);
-       return pt;
-}
-#endif  /*  0  */
-
-void drm_ioremapfree (void *pt, unsigned long size, drm_device_t * dev) {
-       int alloc_count;
-       int free_count;
-
-       if (!pt)
-               DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
-                             "Attempt to free NULL pointer\n");
-       else
-               drm_ioremapfree(pt, size, dev);
-
-       spin_lock(&drm_mem_lock);
-       drm_mem_stats[DRM_MEM_MAPPINGS].bytes_freed += size;
-       free_count = ++drm_mem_stats[DRM_MEM_MAPPINGS].free_count;
-       alloc_count = drm_mem_stats[DRM_MEM_MAPPINGS].succeed_count;
-       spin_unlock(&drm_mem_lock);
-       if (free_count > alloc_count) {
-               DRM_MEM_ERROR(DRM_MEM_MAPPINGS,
-                             "Excess frees: %d frees, %d allocs\n",
-                             free_count, alloc_count);
-       }
-}
-
 #if __OS_HAS_AGP
 
 DRM_AGP_MEM *drm_alloc_agp (drm_device_t *dev, int pages, u32 type) {
index 617526b..9b46b85 100644 (file)
  */
 
 #include "drmP.h"
+#include <linux/slab.h>
+
+unsigned long drm_mm_tail_space(drm_mm_t *mm)
+{
+       struct list_head *tail_node;
+       drm_mm_node_t *entry;
+
+       tail_node = mm->ml_entry.prev;
+       entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+       if (!entry->free)
+               return 0;
+
+       return entry->size;
+}
+
+int drm_mm_remove_space_from_tail(drm_mm_t *mm, unsigned long size)
+{
+       struct list_head *tail_node;
+       drm_mm_node_t *entry;
+
+       tail_node = mm->ml_entry.prev;
+       entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+       if (!entry->free)
+               return -ENOMEM;
+
+       if (entry->size <= size)
+               return -ENOMEM;
+
+       entry->size -= size;
+       return 0;
+}
+
+
+static int drm_mm_create_tail_node(drm_mm_t *mm,
+                           unsigned long start,
+                           unsigned long size)
+{
+       drm_mm_node_t *child;
+
+       child = (drm_mm_node_t *)
+               drm_alloc(sizeof(*child), DRM_MEM_MM);
+       if (!child)
+               return -ENOMEM;
+
+       child->free = 1;
+       child->size = size;
+       child->start = start;
+       child->mm = mm;
+
+       list_add_tail(&child->ml_entry, &mm->ml_entry);
+       list_add_tail(&child->fl_entry, &mm->fl_entry);
+
+       return 0;
+}
+
+
+int drm_mm_add_space_to_tail(drm_mm_t *mm, unsigned long size)
+{
+       struct list_head *tail_node;
+       drm_mm_node_t *entry;
+
+       tail_node = mm->ml_entry.prev;
+       entry = list_entry(tail_node, drm_mm_node_t, ml_entry);
+       if (!entry->free) {
+               return drm_mm_create_tail_node(mm, entry->start + entry->size, size);
+       }
+       entry->size += size;
+       return 0;
+}
+
+static drm_mm_node_t *drm_mm_split_at_start(drm_mm_node_t *parent,
+                                           unsigned long size)
+{
+       drm_mm_node_t *child;
+
+       child = (drm_mm_node_t *)
+               drm_alloc(sizeof(*child), DRM_MEM_MM);
+       if (!child)
+               return NULL;
+
+       INIT_LIST_HEAD(&child->fl_entry);
+
+       child->free = 0;
+       child->size = size;
+       child->start = parent->start;
+       child->mm = parent->mm;
+
+       list_add_tail(&child->ml_entry, &parent->ml_entry);
+       INIT_LIST_HEAD(&child->fl_entry);
+
+       parent->size -= size;
+       parent->start += size;
+       return child;
+}
+
+
 
 drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
                                unsigned long size, unsigned alignment)
 {
 
+       drm_mm_node_t *align_splitoff = NULL;
        drm_mm_node_t *child;
+       unsigned tmp = 0;
 
        if (alignment)
-               size += alignment - 1;
+               tmp = parent->start % alignment;
+
+       if (tmp) {
+               align_splitoff = drm_mm_split_at_start(parent, alignment - tmp);
+               if (!align_splitoff)
+                       return NULL;
+       }
 
        if (parent->size == size) {
                list_del_init(&parent->fl_entry);
                parent->free = 0;
                return parent;
        } else {
-               child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
-               if (!child)
-                       return NULL;
-
-               INIT_LIST_HEAD(&child->ml_entry);
-               INIT_LIST_HEAD(&child->fl_entry);
+               child = drm_mm_split_at_start(parent, size);
+       }
 
-               child->free = 0;
-               child->size = size;
-               child->start = parent->start;
+       if (align_splitoff)
+               drm_mm_put_block(align_splitoff);
 
-               list_add_tail(&child->ml_entry, &parent->ml_entry);
-               parent->size -= size;
-               parent->start += size;
-       }
        return child;
 }
 
@@ -80,12 +175,12 @@ drm_mm_node_t *drm_mm_get_block(drm_mm_node_t * parent,
  * Otherwise add to the free stack.
  */
 
-void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
+void drm_mm_put_block(drm_mm_node_t * cur)
 {
 
-       drm_mm_node_t *list_root = &mm->root_node;
+       drm_mm_t *mm = cur->mm;
        struct list_head *cur_head = &cur->ml_entry;
-       struct list_head *root_head = &list_root->ml_entry;
+       struct list_head *root_head = &mm->ml_entry;
        drm_mm_node_t *prev_node = NULL;
        drm_mm_node_t *next_node;
 
@@ -116,7 +211,7 @@ void drm_mm_put_block(drm_mm_t * mm, drm_mm_node_t * cur)
        }
        if (!merged) {
                cur->free = 1;
-               list_add(&cur->fl_entry, &list_root->fl_entry);
+               list_add(&cur->fl_entry, &mm->fl_entry);
        } else {
                list_del(&cur->ml_entry);
                drm_free(cur, sizeof(*cur), DRM_MEM_MM);
@@ -128,20 +223,30 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
                                  unsigned alignment, int best_match)
 {
        struct list_head *list;
-       const struct list_head *free_stack = &mm->root_node.fl_entry;
+       const struct list_head *free_stack = &mm->fl_entry;
        drm_mm_node_t *entry;
        drm_mm_node_t *best;
        unsigned long best_size;
+       unsigned wasted;
 
        best = NULL;
        best_size = ~0UL;
 
-       if (alignment)
-               size += alignment - 1;
-
        list_for_each(list, free_stack) {
                entry = list_entry(list, drm_mm_node_t, fl_entry);
-               if (entry->size >= size) {
+               wasted = 0;
+
+               if (entry->size < size)
+                       continue;
+
+               if (alignment) {
+                       register unsigned tmp = entry->start % alignment;
+                       if (tmp)
+                               wasted += alignment - tmp;
+               }
+
+
+               if (entry->size >= size + wasted) {
                        if (!best_match)
                                return entry;
                        if (size < best_size) {
@@ -154,40 +259,32 @@ drm_mm_node_t *drm_mm_search_free(const drm_mm_t * mm,
        return best;
 }
 
-int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+int drm_mm_clean(drm_mm_t * mm)
 {
-       drm_mm_node_t *child;
-
-       INIT_LIST_HEAD(&mm->root_node.ml_entry);
-       INIT_LIST_HEAD(&mm->root_node.fl_entry);
-       child = (drm_mm_node_t *) drm_alloc(sizeof(*child), DRM_MEM_MM);
-       if (!child)
-               return -ENOMEM;
-
-       INIT_LIST_HEAD(&child->ml_entry);
-       INIT_LIST_HEAD(&child->fl_entry);
+       struct list_head *head = &mm->ml_entry;
 
-       child->start = start;
-       child->size = size;
-       child->free = 1;
+       return (head->next->next == head);
+}
 
-       list_add(&child->fl_entry, &mm->root_node.fl_entry);
-       list_add(&child->ml_entry, &mm->root_node.ml_entry);
+int drm_mm_init(drm_mm_t * mm, unsigned long start, unsigned long size)
+{
+       INIT_LIST_HEAD(&mm->ml_entry);
+       INIT_LIST_HEAD(&mm->fl_entry);
 
-       return 0;
+       return drm_mm_create_tail_node(mm, start, size);
 }
 
 EXPORT_SYMBOL(drm_mm_init);
 
 void drm_mm_takedown(drm_mm_t * mm)
 {
-       struct list_head *bnode = mm->root_node.fl_entry.next;
+       struct list_head *bnode = mm->fl_entry.next;
        drm_mm_node_t *entry;
 
        entry = list_entry(bnode, drm_mm_node_t, fl_entry);
 
-       if (entry->ml_entry.next != &mm->root_node.ml_entry ||
-           entry->fl_entry.next != &mm->root_node.fl_entry) {
+       if (entry->ml_entry.next != &mm->ml_entry ||
+           entry->fl_entry.next != &mm->fl_entry) {
                DRM_ERROR("Memory manager not clean. Delaying takedown\n");
                return;
        }
index 09398d5..ad54b84 100644 (file)
        {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x3118, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \
        {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x3108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x3304, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
        {0x1106, 0x3344, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
-       {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+       {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \
        {0, 0, 0}
 
 #define i810_PCI_IDS \
index 62d5fe1..7fd0da7 100644 (file)
@@ -500,7 +500,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
        for (pt = dev->vmalist; pt; pt = pt->next) {
                if (!(vma = pt->vma))
                        continue;
-               DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx",
+               DRM_PROC_PRINT("\n%5d 0x%08lx-0x%08lx %c%c%c%c%c%c 0x%08lx000",
                               pt->pid,
                               vma->vm_start,
                               vma->vm_end,
@@ -510,7 +510,7 @@ static int drm__vma_info(char *buf, char **start, off_t offset, int request,
                               vma->vm_flags & VM_MAYSHARE ? 's' : 'p',
                               vma->vm_flags & VM_LOCKED ? 'l' : '-',
                               vma->vm_flags & VM_IO ? 'i' : '-',
-                              vma->vm_pgoff << PAGE_SHIFT);
+                              vma->vm_pgoff);
 
 #if defined(__i386__)
                pgprot = pgprot_val(vma->vm_page_prot);
index 19c81d2..e15db6d 100644 (file)
@@ -101,10 +101,9 @@ static void *drm_sman_mm_allocate(void *private, unsigned long size,
 
 static void drm_sman_mm_free(void *private, void *ref)
 {
-       drm_mm_t *mm = (drm_mm_t *) private;
        drm_mm_node_t *node = (drm_mm_node_t *) ref;
 
-       drm_mm_put_block(mm, node);
+       drm_mm_put_block(node);
 }
 
 static void drm_sman_mm_destroy(void *private)
index b9cfc07..54a6328 100644 (file)
@@ -70,7 +70,7 @@ static __inline__ struct page *drm_do_vm_nopage(struct vm_area_struct *vma,
        if (!dev->agp || !dev->agp->cant_use_aperture)
                goto vm_nopage_error;
 
-       if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash))
+       if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash))
                goto vm_nopage_error;
 
        r_list = drm_hash_entry(hash, drm_map_list_t, hash);
@@ -227,7 +227,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
                                                           map->size);
                                        DRM_DEBUG("mtrr_del = %d\n", retcode);
                                }
-                               drm_ioremapfree(map->handle, map->size, dev);
+                               iounmap(map->handle);
                                break;
                        case _DRM_SHM:
                                vfree(map->handle);
@@ -463,8 +463,8 @@ static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
        lock_kernel();
        dev = priv->head->dev;
        dma = dev->dma;
-       DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
-                 vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
+       DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
+                 vma->vm_start, vma->vm_end, vma->vm_pgoff);
 
        /* Length must match exact page count */
        if (!dma || (length >> PAGE_SHIFT) != dma->page_count) {
@@ -537,8 +537,8 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
        unsigned long offset = 0;
        drm_hash_item_t *hash;
 
-       DRM_DEBUG("start = 0x%lx, end = 0x%lx, offset = 0x%lx\n",
-                 vma->vm_start, vma->vm_end, vma->vm_pgoff << PAGE_SHIFT);
+       DRM_DEBUG("start = 0x%lx, end = 0x%lx, page offset = 0x%lx\n",
+                 vma->vm_start, vma->vm_end, vma->vm_pgoff);
 
        if (!priv->authenticated)
                return -EACCES;
@@ -547,7 +547,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
         * the AGP mapped at physical address 0
         * --BenH.
         */
-       if (!(vma->vm_pgoff << PAGE_SHIFT)
+       if (!vma->vm_pgoff
 #if __OS_HAS_AGP
            && (!dev->agp
                || dev->agp->agp_info.device->vendor != PCI_VENDOR_ID_APPLE)
@@ -555,7 +555,7 @@ int drm_mmap(struct file *filp, struct vm_area_struct *vma)
            )
                return drm_mmap_dma(filp, vma);
 
-       if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff << PAGE_SHIFT, &hash)) {
+       if (drm_ht_find_item(&dev->map_hash, vma->vm_pgoff, &hash)) {
                DRM_ERROR("Could not find map\n");
                return -EINVAL;
        }
index fa2de70..60cb4e4 100644 (file)
@@ -219,8 +219,7 @@ static int i810_dma_cleanup(drm_device_t * dev)
                    (drm_i810_private_t *) dev->dev_private;
 
                if (dev_priv->ring.virtual_start) {
-                       drm_ioremapfree((void *)dev_priv->ring.virtual_start,
-                                       dev_priv->ring.Size, dev);
+                       drm_core_ioremapfree(&dev_priv->ring.map, dev);
                }
                if (dev_priv->hw_status_page) {
                        pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -236,9 +235,9 @@ static int i810_dma_cleanup(drm_device_t * dev)
                for (i = 0; i < dma->buf_count; i++) {
                        drm_buf_t *buf = dma->buflist[i];
                        drm_i810_buf_priv_t *buf_priv = buf->dev_private;
+
                        if (buf_priv->kernel_virtual && buf->total)
-                               drm_ioremapfree(buf_priv->kernel_virtual,
-                                               buf->total, dev);
+                               drm_core_ioremapfree(&buf_priv->map, dev);
                }
        }
        return 0;
@@ -311,8 +310,15 @@ static int i810_freelist_init(drm_device_t * dev, drm_i810_private_t * dev_priv)
 
                *buf_priv->in_use = I810_BUF_FREE;
 
-               buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
-                                                      buf->total, dev);
+               buf_priv->map.offset = buf->bus_address;
+               buf_priv->map.size = buf->total;
+               buf_priv->map.type = _DRM_AGP;
+               buf_priv->map.flags = 0;
+               buf_priv->map.mtrr = 0;
+
+               drm_core_ioremap(&buf_priv->map, dev);
+               buf_priv->kernel_virtual = buf_priv->map.handle;
+
        }
        return 0;
 }
@@ -363,18 +369,24 @@ static int i810_dma_initialize(drm_device_t * dev,
        dev_priv->ring.End = init->ring_end;
        dev_priv->ring.Size = init->ring_size;
 
-       dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
-                                                  init->ring_start,
-                                                  init->ring_size, dev);
+       dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
+       dev_priv->ring.map.size = init->ring_size;
+       dev_priv->ring.map.type = _DRM_AGP;
+       dev_priv->ring.map.flags = 0;
+       dev_priv->ring.map.mtrr = 0;
 
-       if (dev_priv->ring.virtual_start == NULL) {
+       drm_core_ioremap(&dev_priv->ring.map, dev);
+
+       if (dev_priv->ring.map.handle == NULL) {
                dev->dev_private = (void *)dev_priv;
                i810_dma_cleanup(dev);
                DRM_ERROR("can not ioremap virtual address for"
                          " ring buffer\n");
-               return -ENOMEM;
+               return DRM_ERR(ENOMEM);
        }
 
+       dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
        dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
 
        dev_priv->w = init->w;
index e8cf3ff..e6df49f 100644 (file)
@@ -61,6 +61,7 @@ typedef struct drm_i810_buf_priv {
        int currently_mapped;
        void *virtual;
        void *kernel_virtual;
+       drm_local_map_t map;
 } drm_i810_buf_priv_t;
 
 typedef struct _drm_i810_ring_buffer {
@@ -72,6 +73,7 @@ typedef struct _drm_i810_ring_buffer {
        int head;
        int tail;
        int space;
+       drm_local_map_t map;
 } drm_i810_ring_buffer_t;
 
 typedef struct drm_i810_private {
index 4f0e574..9522445 100644 (file)
@@ -223,8 +223,7 @@ static int i830_dma_cleanup(drm_device_t * dev)
                    (drm_i830_private_t *) dev->dev_private;
 
                if (dev_priv->ring.virtual_start) {
-                       drm_ioremapfree((void *)dev_priv->ring.virtual_start,
-                                       dev_priv->ring.Size, dev);
+                       drm_core_ioremapfree(&dev_priv->ring.map, dev);
                }
                if (dev_priv->hw_status_page) {
                        pci_free_consistent(dev->pdev, PAGE_SIZE,
@@ -242,8 +241,7 @@ static int i830_dma_cleanup(drm_device_t * dev)
                        drm_buf_t *buf = dma->buflist[i];
                        drm_i830_buf_priv_t *buf_priv = buf->dev_private;
                        if (buf_priv->kernel_virtual && buf->total)
-                               drm_ioremapfree(buf_priv->kernel_virtual,
-                                               buf->total, dev);
+                               drm_core_ioremapfree(&buf_priv->map, dev);
                }
        }
        return 0;
@@ -320,8 +318,14 @@ static int i830_freelist_init(drm_device_t * dev, drm_i830_private_t * dev_priv)
 
                *buf_priv->in_use = I830_BUF_FREE;
 
-               buf_priv->kernel_virtual = drm_ioremap(buf->bus_address,
-                                                      buf->total, dev);
+               buf_priv->map.offset = buf->bus_address;
+               buf_priv->map.size = buf->total;
+               buf_priv->map.type = _DRM_AGP;
+               buf_priv->map.flags = 0;
+               buf_priv->map.mtrr = 0;
+
+               drm_core_ioremap(&buf_priv->map, dev);
+               buf_priv->kernel_virtual = buf_priv->map.handle;
        }
        return 0;
 }
@@ -373,18 +377,24 @@ static int i830_dma_initialize(drm_device_t * dev,
        dev_priv->ring.End = init->ring_end;
        dev_priv->ring.Size = init->ring_size;
 
-       dev_priv->ring.virtual_start = drm_ioremap(dev->agp->base +
-                                                  init->ring_start,
-                                                  init->ring_size, dev);
+       dev_priv->ring.map.offset = dev->agp->base + init->ring_start;
+       dev_priv->ring.map.size = init->ring_size;
+       dev_priv->ring.map.type = _DRM_AGP;
+       dev_priv->ring.map.flags = 0;
+       dev_priv->ring.map.mtrr = 0;
+
+       drm_core_ioremap(&dev_priv->ring.map, dev);
 
-       if (dev_priv->ring.virtual_start == NULL) {
+       if (dev_priv->ring.map.handle == NULL) {
                dev->dev_private = (void *)dev_priv;
                i830_dma_cleanup(dev);
                DRM_ERROR("can not ioremap virtual address for"
                          " ring buffer\n");
-               return -ENOMEM;
+               return DRM_ERR(ENOMEM);
        }
 
+       dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
+
        dev_priv->ring.tail_mask = dev_priv->ring.Size - 1;
 
        dev_priv->w = init->w;
index 85bc5be..e91f94a 100644 (file)
@@ -68,6 +68,7 @@ typedef struct drm_i830_buf_priv {
        int currently_mapped;
        void __user *virtual;
        void *kernel_virtual;
+       drm_local_map_t map;
 } drm_i830_buf_priv_t;
 
 typedef struct _drm_i830_ring_buffer {
@@ -79,6 +80,7 @@ typedef struct _drm_i830_ring_buffer {
        int head;
        int tail;
        int space;
+       drm_local_map_t map;
 } drm_i830_ring_buffer_t;
 
 typedef struct drm_i830_private {
index a691ae7..c0539c6 100644 (file)
@@ -190,6 +190,11 @@ static int via_initialize(drm_device_t * dev,
                return DRM_ERR(EFAULT);
        }
 
+       if (dev_priv->chipset == VIA_DX9_0) {
+               DRM_ERROR("AGP DMA is not supported on this chip\n");
+               return DRM_ERR(EINVAL);
+       }
+
        dev_priv->ring.map.offset = dev->agp->base + init->offset;
        dev_priv->ring.map.size = init->size;
        dev_priv->ring.map.type = 0;
@@ -480,6 +485,7 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
                        VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
                        VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
                        VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
+                       VIA_READ(VIA_REG_TRANSPACE);
                }
        }
        return paused;
@@ -557,8 +563,9 @@ static void via_cmdbuf_start(drm_via_private_t * dev_priv)
 
        VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
        VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
-
+       DRM_WRITEMEMORYBARRIER();
        VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
+       VIA_READ(VIA_REG_TRANSPACE);
 }
 
 static void via_pad_cache(drm_via_private_t * dev_priv, int qwords)
index 806f9ce..2054d57 100644 (file)
@@ -218,7 +218,9 @@ via_fire_dmablit(drm_device_t *dev, drm_via_sg_info_t *vsg, int engine)
        VIA_WRITE(VIA_PCI_DMA_MR0  + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE);
        VIA_WRITE(VIA_PCI_DMA_BCR0 + engine*0x10, 0);
        VIA_WRITE(VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start);
+       DRM_WRITEMEMORYBARRIER();
        VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS);
+       VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04);
 }
 
 /*
index d21b5b7..8b8778d 100644 (file)
 
 #define DRIVER_NAME            "via"
 #define DRIVER_DESC            "VIA Unichrome / Pro"
-#define DRIVER_DATE            "20060529"
+#define DRIVER_DATE            "20061227"
 
 #define DRIVER_MAJOR           2
-#define DRIVER_MINOR           10
+#define DRIVER_MINOR           11
 #define DRIVER_PATCHLEVEL      0
 
 #include "via_verifier.h"
@@ -79,7 +79,7 @@ typedef struct drm_via_private {
        char pci_buf[VIA_PCI_BUF_SIZE];
        const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
        uint32_t num_fire_offsets;
-       int pro_group_a;
+       int chipset;
        drm_via_irq_t via_irqs[VIA_NUM_IRQS];
        unsigned num_irqs;
        maskarray_t *irq_masks;
@@ -96,8 +96,9 @@ typedef struct drm_via_private {
 } drm_via_private_t;
 
 enum via_family {
-       VIA_OTHER = 0,
-       VIA_PRO_GROUP_A,
+  VIA_OTHER = 0,     /* Baseline */
+  VIA_PRO_GROUP_A,   /* Another video engine and DMA commands */
+  VIA_DX9_0          /* Same video as pro_group_a, but 3D is unsupported */
 };
 
 /* VIA MMIO register access */
index c33d068..1ac5941 100644 (file)
@@ -258,12 +258,16 @@ void via_driver_irq_preinstall(drm_device_t * dev)
                dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
                dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
 
-               dev_priv->irq_masks = (dev_priv->pro_group_a) ?
-                   via_pro_group_a_irqs : via_unichrome_irqs;
-               dev_priv->num_irqs = (dev_priv->pro_group_a) ?
-                   via_num_pro_group_a : via_num_unichrome;
-               dev_priv->irq_map = (dev_priv->pro_group_a) ?
-                       via_irqmap_pro_group_a : via_irqmap_unichrome;
+               if (dev_priv->chipset == VIA_PRO_GROUP_A ||
+                   dev_priv->chipset == VIA_DX9_0) {
+                       dev_priv->irq_masks = via_pro_group_a_irqs;
+                       dev_priv->num_irqs = via_num_pro_group_a;
+                       dev_priv->irq_map = via_irqmap_pro_group_a;
+               } else {
+                       dev_priv->irq_masks = via_unichrome_irqs;
+                       dev_priv->num_irqs = via_num_unichrome;
+                       dev_priv->irq_map = via_irqmap_unichrome;
+               }
 
                for (i = 0; i < dev_priv->num_irqs; ++i) {
                        atomic_set(&cur_irq->irq_received, 0);
index 782011e..4e3fc07 100644 (file)
@@ -106,8 +106,7 @@ int via_driver_load(drm_device_t *dev, unsigned long chipset)
 
        dev->dev_private = (void *)dev_priv;
 
-       if (chipset == VIA_PRO_GROUP_A)
-               dev_priv->pro_group_a = 1;
+       dev_priv->chipset = chipset;
 
        ret = drm_sman_init(&dev_priv->sman, 2, 12, 8);
        if (ret) {
index 70c897c..2e7e080 100644 (file)
@@ -306,6 +306,7 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
                        unsigned long lo = ~0, hi = 0, tmp;
                        uint32_t *addr, *pitch, *height, tex;
                        unsigned i;
+                       int npot;
 
                        if (end > 9)
                                end = 9;
@@ -316,12 +317,15 @@ static __inline__ int finish_current_sequence(drm_via_state_t * cur_seq)
                            &(cur_seq->t_addr[tex = cur_seq->texture][start]);
                        pitch = &(cur_seq->pitch[tex][start]);
                        height = &(cur_seq->height[tex][start]);
-
+                       npot = cur_seq->tex_npot[tex];
                        for (i = start; i <= end; ++i) {
                                tmp = *addr++;
                                if (tmp < lo)
                                        lo = tmp;
-                               tmp += (*height++ << *pitch++);
+                               if (i == 0 && npot)
+                                       tmp += (*height++ * *pitch++);
+                               else
+                                       tmp += (*height++ << *pitch++);
                                if (tmp > hi)
                                        hi = tmp;
                        }
@@ -443,13 +447,21 @@ investigate_hazard(uint32_t cmd, hazard_t hz, drm_via_state_t * cur_seq)
                return 0;
        case check_texture_addr3:
                cur_seq->unfinished = tex_address;
-               tmp = ((cmd >> 24) - 0x2B);
-               cur_seq->pitch[cur_seq->texture][tmp] =
-                   (cmd & 0x00F00000) >> 20;
-               if (!tmp && (cmd & 0x000FFFFF)) {
-                       DRM_ERROR
-                           ("Unimplemented texture level 0 pitch mode.\n");
-                       return 2;
+               tmp = ((cmd >> 24) - HC_SubA_HTXnL0Pit);
+               if (tmp == 0 &&
+                   (cmd & HC_HTXnEnPit_MASK)) {
+                       cur_seq->pitch[cur_seq->texture][tmp] =
+                               (cmd & HC_HTXnLnPit_MASK);
+                       cur_seq->tex_npot[cur_seq->texture] = 1;
+               } else {
+                       cur_seq->pitch[cur_seq->texture][tmp] =
+                               (cmd & HC_HTXnLnPitE_MASK) >> HC_HTXnLnPitE_SHIFT;
+                       cur_seq->tex_npot[cur_seq->texture] = 0;
+                       if (cmd & 0x000FFFFF) {
+                               DRM_ERROR
+                                       ("Unimplemented texture level 0 pitch mode.\n");
+                               return 2;
+                       }
                }
                return 0;
        case check_texture_addr4:
@@ -961,7 +973,13 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
        uint32_t cmd;
        const uint32_t *buf_end = buf + (size >> 2);
        verifier_state_t state = state_command;
-       int pro_group_a = dev_priv->pro_group_a;
+       int cme_video;
+       int supported_3d;
+
+       cme_video = (dev_priv->chipset == VIA_PRO_GROUP_A ||
+                    dev_priv->chipset == VIA_DX9_0);
+
+       supported_3d = dev_priv->chipset != VIA_DX9_0;
 
        hc_state->dev = dev;
        hc_state->unfinished = no_sequence;
@@ -986,17 +1004,21 @@ via_verify_command_stream(const uint32_t * buf, unsigned int size,
                        state = via_check_vheader6(&buf, buf_end);
                        break;
                case state_command:
-                       if (HALCYON_HEADER2 == (cmd = *buf))
+                       if ((HALCYON_HEADER2 == (cmd = *buf)) &&
+                           supported_3d)
                                state = state_header2;
                        else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
                                state = state_header1;
-                       else if (pro_group_a
+                       else if (cme_video
                                 && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
                                state = state_vheader5;
-                       else if (pro_group_a
+                       else if (cme_video
                                 && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
                                state = state_vheader6;
-                       else {
+                       else if ((cmd == HALCYON_HEADER2) && !supported_3d) {
+                               DRM_ERROR("Accelerated 3D is not supported on this chipset yet.\n");
+                               state = state_error;
+                       } else {
                                DRM_ERROR
                                    ("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
                                     cmd);
index 256590f..b77f59d 100644 (file)
@@ -43,6 +43,7 @@ typedef struct {
        uint32_t tex_level_lo[2];
        uint32_t tex_level_hi[2];
        uint32_t tex_palette_size[2];
+       uint32_t tex_npot[2];
        drm_via_sequence_t unfinished;
        int agp_texture;
        int multitex;
index f1afd26..a7b33d2 100644 (file)
@@ -1802,7 +1802,7 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
            return -ENODEV;
        }
 
-       if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
+       if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
                addr_space = IPMI_MEM_ADDR_SPACE;
        else
                addr_space = IPMI_IO_ADDR_SPACE;
@@ -1848,19 +1848,19 @@ static __devinit int try_init_acpi(struct SPMITable *spmi)
                info->irq_setup = NULL;
        }
 
-       if (spmi->addr.register_bit_width) {
+       if (spmi->addr.bit_width) {
                /* A (hopefully) properly formed register bit width. */
-               info->io.regspacing = spmi->addr.register_bit_width / 8;
+               info->io.regspacing = spmi->addr.bit_width / 8;
        } else {
                info->io.regspacing = DEFAULT_REGSPACING;
        }
        info->io.regsize = info->io.regspacing;
-       info->io.regshift = spmi->addr.register_bit_offset;
+       info->io.regshift = spmi->addr.bit_offset;
 
-       if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+       if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
                info->io_setup = mem_setup;
                info->io.addr_type = IPMI_IO_ADDR_SPACE;
-       } else if (spmi->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
+       } else if (spmi->addr.space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
                info->io_setup = port_setup;
                info->io.addr_type = IPMI_MEM_ADDR_SPACE;
        } else {
@@ -1888,10 +1888,8 @@ static __devinit void acpi_find_bmc(void)
                return;
 
        for (i = 0; ; i++) {
-               status = acpi_get_firmware_table("SPMI", i+1,
-                                                ACPI_LOGICAL_ADDRESSING,
-                                                (struct acpi_table_header **)
-                                                &spmi);
+               status = acpi_get_table(ACPI_SIG_SPMI, i+1,
+                                       (struct acpi_table_header **)&spmi);
                if (status != AE_OK)
                        return;
 
index a611972..7fca5f4 100644 (file)
@@ -372,10 +372,8 @@ static int read_log(struct tpm_bios_log *log)
        }
 
        /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
-       status = acpi_get_firmware_table(ACPI_TCPA_SIG, 1,
-                                        ACPI_LOGICAL_ADDRESSING,
-                                        (struct acpi_table_header **)
-                                        &buff);
+       status = acpi_get_table(ACPI_SIG_TCPA, 1,
+                               (struct acpi_table_header **)&buff);
 
        if (ACPI_FAILURE(status)) {
                printk(KERN_ERR "%s: ERROR - Could not get TCPA table\n",
@@ -409,7 +407,7 @@ static int read_log(struct tpm_bios_log *log)
 
        log->bios_event_log_end = log->bios_event_log + len;
 
-       acpi_os_map_memory(start, len, (void *) &virt);
+       virt = acpi_os_map_memory(start, len);
 
        memcpy(log->bios_event_log, virt, len);
 
index 879250d..ff8c4be 100644 (file)
@@ -51,6 +51,8 @@ config CRYPTO_DEV_PADLOCK_SHA
          If unsure say M. The compiled module will be
          called padlock-sha.ko
 
+source "arch/s390/crypto/Kconfig"
+
 config CRYPTO_DEV_GEODE
        tristate "Support for the Geode LX AES engine"
        depends on CRYPTO && X86_32 && PCI
index c2ad72f..2b4b76e 100644 (file)
@@ -26,7 +26,7 @@ setup_serial_console(struct pcdp_uart *uart)
        static char options[64], *p = options;
        char parity;
 
-       mmio = (uart->addr.address_space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
+       mmio = (uart->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY);
        p += sprintf(p, "console=uart,%s,0x%lx",
                mmio ? "mmio" : "io", uart->addr.address);
        if (uart->baud) {
index ec796ad..850788f 100644 (file)
@@ -22,5 +22,19 @@ config HID
 
          If unsure, say Y
 
+config HID_DEBUG
+       bool "HID debugging support"
+       depends on HID
+       ---help---
+       This option lets the HID layer output diagnostics about its internal
+       state, resolve HID usages, dump HID fields, etc. Individual HID drivers
+       use this debugging facility to output information about individual HID
+       devices, etc.
+
+       This feature is useful for those who are either debugging the HID parser
+       or any HID hardware device.
+
+       If unsure, say N
+
 endmenu
 
index 6432392..52e97d8 100644 (file)
@@ -1,15 +1,8 @@
 #
 # Makefile for the HID driver
 #
-
-# Multipart objects.
-hid-objs       := hid-core.o hid-input.o
-
-# Optional parts of multipart objects.
+hid-objs                       := hid-core.o hid-input.o
 
 obj-$(CONFIG_HID)              += hid.o
-
-ifeq ($(CONFIG_INPUT_DEBUG),y)
-EXTRA_CFLAGS += -DDEBUG
-endif
+hid-$(CONFIG_HID_DEBUG)                += hid-debug.o
 
index 49f18f5..8c7d48e 100644 (file)
 #include <linux/input.h>
 #include <linux/wait.h>
 
-#undef DEBUG
-#undef DEBUG_DATA
-
 #include <linux/hid.h>
 #include <linux/hiddev.h>
+#include <linux/hid-debug.h>
 
 /*
  * Version Information
@@ -951,7 +949,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
                return -1;
        }
 
-#ifdef DEBUG_DATA
+#ifdef CONFIG_HID_DEBUG
        printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un");
 #endif
 
@@ -961,7 +959,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
                size--;
        }
 
-#ifdef DEBUG_DATA
+#ifdef CONFIG_HID_DEBUG
        {
                int i;
                printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, size);
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
new file mode 100644 (file)
index 0000000..89241be
--- /dev/null
@@ -0,0 +1,764 @@
+/*
+ * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $
+ *
+ *  (c) 1999 Andreas Gal               <gal@cs.uni-magdeburg.de>
+ *  (c) 2000-2001 Vojtech Pavlik       <vojtech@ucw.cz>
+ *  (c) 2007 Jiri Kosina
+ *
+ *  Some debug stuff for the HID parser.
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/hid.h>
+
+struct hid_usage_entry {
+       unsigned  page;
+       unsigned  usage;
+       char     *description;
+};
+
+static const struct hid_usage_entry hid_usage_table[] = {
+  {  0,      0, "Undefined" },
+  {  1,      0, "GenericDesktop" },
+    {0, 0x01, "Pointer"},
+    {0, 0x02, "Mouse"},
+    {0, 0x04, "Joystick"},
+    {0, 0x05, "GamePad"},
+    {0, 0x06, "Keyboard"},
+    {0, 0x07, "Keypad"},
+    {0, 0x08, "MultiAxis"},
+      {0, 0x30, "X"},
+      {0, 0x31, "Y"},
+      {0, 0x32, "Z"},
+      {0, 0x33, "Rx"},
+      {0, 0x34, "Ry"},
+      {0, 0x35, "Rz"},
+      {0, 0x36, "Slider"},
+      {0, 0x37, "Dial"},
+      {0, 0x38, "Wheel"},
+      {0, 0x39, "HatSwitch"},
+    {0, 0x3a, "CountedBuffer"},
+      {0, 0x3b, "ByteCount"},
+      {0, 0x3c, "MotionWakeup"},
+      {0, 0x3d, "Start"},
+      {0, 0x3e, "Select"},
+      {0, 0x40, "Vx"},
+      {0, 0x41, "Vy"},
+      {0, 0x42, "Vz"},
+      {0, 0x43, "Vbrx"},
+      {0, 0x44, "Vbry"},
+      {0, 0x45, "Vbrz"},
+      {0, 0x46, "Vno"},
+    {0, 0x80, "SystemControl"},
+      {0, 0x81, "SystemPowerDown"},
+      {0, 0x82, "SystemSleep"},
+      {0, 0x83, "SystemWakeUp"},
+      {0, 0x84, "SystemContextMenu"},
+      {0, 0x85, "SystemMainMenu"},
+      {0, 0x86, "SystemAppMenu"},
+      {0, 0x87, "SystemMenuHelp"},
+      {0, 0x88, "SystemMenuExit"},
+      {0, 0x89, "SystemMenuSelect"},
+      {0, 0x8a, "SystemMenuRight"},
+      {0, 0x8b, "SystemMenuLeft"},
+      {0, 0x8c, "SystemMenuUp"},
+      {0, 0x8d, "SystemMenuDown"},
+      {0, 0x90, "D-PadUp"},
+      {0, 0x91, "D-PadDown"},
+      {0, 0x92, "D-PadRight"},
+      {0, 0x93, "D-PadLeft"},
+  {  2, 0, "Simulation" },
+      {0, 0xb0, "Aileron"},
+      {0, 0xb1, "AileronTrim"},
+      {0, 0xb2, "Anti-Torque"},
+      {0, 0xb3, "Autopilot"},
+      {0, 0xb4, "Chaff"},
+      {0, 0xb5, "Collective"},
+      {0, 0xb6, "DiveBrake"},
+      {0, 0xb7, "ElectronicCountermeasures"},
+      {0, 0xb8, "Elevator"},
+      {0, 0xb9, "ElevatorTrim"},
+      {0, 0xba, "Rudder"},
+      {0, 0xbb, "Throttle"},
+      {0, 0xbc, "FlightCommunications"},
+      {0, 0xbd, "FlareRelease"},
+      {0, 0xbe, "LandingGear"},
+      {0, 0xbf, "ToeBrake"},
+  {  7, 0, "Keyboard" },
+  {  8, 0, "LED" },
+      {0, 0x01, "NumLock"},
+      {0, 0x02, "CapsLock"},
+      {0, 0x03, "ScrollLock"},
+      {0, 0x04, "Compose"},
+      {0, 0x05, "Kana"},
+      {0, 0x4b, "GenericIndicator"},
+  {  9, 0, "Button" },
+  { 10, 0, "Ordinal" },
+  { 12, 0, "Consumer" },
+      {0, 0x238, "HorizontalWheel"},
+  { 13, 0, "Digitizers" },
+    {0, 0x01, "Digitizer"},
+    {0, 0x02, "Pen"},
+    {0, 0x03, "LightPen"},
+    {0, 0x04, "TouchScreen"},
+    {0, 0x05, "TouchPad"},
+    {0, 0x20, "Stylus"},
+    {0, 0x21, "Puck"},
+    {0, 0x22, "Finger"},
+    {0, 0x30, "TipPressure"},
+    {0, 0x31, "BarrelPressure"},
+    {0, 0x32, "InRange"},
+    {0, 0x33, "Touch"},
+    {0, 0x34, "UnTouch"},
+    {0, 0x35, "Tap"},
+    {0, 0x39, "TabletFunctionKey"},
+    {0, 0x3a, "ProgramChangeKey"},
+    {0, 0x3c, "Invert"},
+    {0, 0x42, "TipSwitch"},
+    {0, 0x43, "SecondaryTipSwitch"},
+    {0, 0x44, "BarrelSwitch"},
+    {0, 0x45, "Eraser"},
+    {0, 0x46, "TabletPick"},
+  { 15, 0, "PhysicalInterfaceDevice" },
+    {0, 0x00, "Undefined"},
+    {0, 0x01, "Physical_Interface_Device"},
+      {0, 0x20, "Normal"},
+    {0, 0x21, "Set_Effect_Report"},
+      {0, 0x22, "Effect_Block_Index"},
+      {0, 0x23, "Parameter_Block_Offset"},
+      {0, 0x24, "ROM_Flag"},
+      {0, 0x25, "Effect_Type"},
+        {0, 0x26, "ET_Constant_Force"},
+        {0, 0x27, "ET_Ramp"},
+        {0, 0x28, "ET_Custom_Force_Data"},
+        {0, 0x30, "ET_Square"},
+        {0, 0x31, "ET_Sine"},
+        {0, 0x32, "ET_Triangle"},
+        {0, 0x33, "ET_Sawtooth_Up"},
+        {0, 0x34, "ET_Sawtooth_Down"},
+        {0, 0x40, "ET_Spring"},
+        {0, 0x41, "ET_Damper"},
+        {0, 0x42, "ET_Inertia"},
+        {0, 0x43, "ET_Friction"},
+      {0, 0x50, "Duration"},
+      {0, 0x51, "Sample_Period"},
+      {0, 0x52, "Gain"},
+      {0, 0x53, "Trigger_Button"},
+      {0, 0x54, "Trigger_Repeat_Interval"},
+      {0, 0x55, "Axes_Enable"},
+        {0, 0x56, "Direction_Enable"},
+      {0, 0x57, "Direction"},
+      {0, 0x58, "Type_Specific_Block_Offset"},
+        {0, 0x59, "Block_Type"},
+        {0, 0x5A, "Set_Envelope_Report"},
+          {0, 0x5B, "Attack_Level"},
+          {0, 0x5C, "Attack_Time"},
+          {0, 0x5D, "Fade_Level"},
+          {0, 0x5E, "Fade_Time"},
+        {0, 0x5F, "Set_Condition_Report"},
+        {0, 0x60, "CP_Offset"},
+        {0, 0x61, "Positive_Coefficient"},
+        {0, 0x62, "Negative_Coefficient"},
+        {0, 0x63, "Positive_Saturation"},
+        {0, 0x64, "Negative_Saturation"},
+        {0, 0x65, "Dead_Band"},
+      {0, 0x66, "Download_Force_Sample"},
+      {0, 0x67, "Isoch_Custom_Force_Enable"},
+      {0, 0x68, "Custom_Force_Data_Report"},
+        {0, 0x69, "Custom_Force_Data"},
+        {0, 0x6A, "Custom_Force_Vendor_Defined_Data"},
+      {0, 0x6B, "Set_Custom_Force_Report"},
+        {0, 0x6C, "Custom_Force_Data_Offset"},
+        {0, 0x6D, "Sample_Count"},
+      {0, 0x6E, "Set_Periodic_Report"},
+        {0, 0x6F, "Offset"},
+        {0, 0x70, "Magnitude"},
+        {0, 0x71, "Phase"},
+        {0, 0x72, "Period"},
+      {0, 0x73, "Set_Constant_Force_Report"},
+        {0, 0x74, "Set_Ramp_Force_Report"},
+        {0, 0x75, "Ramp_Start"},
+        {0, 0x76, "Ramp_End"},
+      {0, 0x77, "Effect_Operation_Report"},
+        {0, 0x78, "Effect_Operation"},
+          {0, 0x79, "Op_Effect_Start"},
+          {0, 0x7A, "Op_Effect_Start_Solo"},
+          {0, 0x7B, "Op_Effect_Stop"},
+          {0, 0x7C, "Loop_Count"},
+      {0, 0x7D, "Device_Gain_Report"},
+        {0, 0x7E, "Device_Gain"},
+    {0, 0x7F, "PID_Pool_Report"},
+      {0, 0x80, "RAM_Pool_Size"},
+      {0, 0x81, "ROM_Pool_Size"},
+      {0, 0x82, "ROM_Effect_Block_Count"},
+      {0, 0x83, "Simultaneous_Effects_Max"},
+      {0, 0x84, "Pool_Alignment"},
+    {0, 0x85, "PID_Pool_Move_Report"},
+      {0, 0x86, "Move_Source"},
+      {0, 0x87, "Move_Destination"},
+      {0, 0x88, "Move_Length"},
+    {0, 0x89, "PID_Block_Load_Report"},
+      {0, 0x8B, "Block_Load_Status"},
+      {0, 0x8C, "Block_Load_Success"},
+      {0, 0x8D, "Block_Load_Full"},
+      {0, 0x8E, "Block_Load_Error"},
+      {0, 0x8F, "Block_Handle"},
+      {0, 0x90, "PID_Block_Free_Report"},
+      {0, 0x91, "Type_Specific_Block_Handle"},
+    {0, 0x92, "PID_State_Report"},
+      {0, 0x94, "Effect_Playing"},
+      {0, 0x95, "PID_Device_Control_Report"},
+        {0, 0x96, "PID_Device_Control"},
+        {0, 0x97, "DC_Enable_Actuators"},
+        {0, 0x98, "DC_Disable_Actuators"},
+        {0, 0x99, "DC_Stop_All_Effects"},
+        {0, 0x9A, "DC_Device_Reset"},
+        {0, 0x9B, "DC_Device_Pause"},
+        {0, 0x9C, "DC_Device_Continue"},
+      {0, 0x9F, "Device_Paused"},
+      {0, 0xA0, "Actuators_Enabled"},
+      {0, 0xA4, "Safety_Switch"},
+      {0, 0xA5, "Actuator_Override_Switch"},
+      {0, 0xA6, "Actuator_Power"},
+    {0, 0xA7, "Start_Delay"},
+    {0, 0xA8, "Parameter_Block_Size"},
+    {0, 0xA9, "Device_Managed_Pool"},
+    {0, 0xAA, "Shared_Parameter_Blocks"},
+    {0, 0xAB, "Create_New_Effect_Report"},
+    {0, 0xAC, "RAM_Pool_Available"},
+  { 0x84, 0, "Power Device" },
+    { 0x84, 0x02, "PresentStatus" },
+    { 0x84, 0x03, "ChangeStatus" },
+    { 0x84, 0x04, "UPS" },
+    { 0x84, 0x05, "PowerSupply" },
+    { 0x84, 0x10, "BatterySystem" },
+    { 0x84, 0x11, "BatterySystemID" },
+    { 0x84, 0x12, "Battery" },
+    { 0x84, 0x13, "BatteryID" },
+    { 0x84, 0x14, "Charger" },
+    { 0x84, 0x15, "ChargerID" },
+    { 0x84, 0x16, "PowerConverter" },
+    { 0x84, 0x17, "PowerConverterID" },
+    { 0x84, 0x18, "OutletSystem" },
+    { 0x84, 0x19, "OutletSystemID" },
+    { 0x84, 0x1a, "Input" },
+    { 0x84, 0x1b, "InputID" },
+    { 0x84, 0x1c, "Output" },
+    { 0x84, 0x1d, "OutputID" },
+    { 0x84, 0x1e, "Flow" },
+    { 0x84, 0x1f, "FlowID" },
+    { 0x84, 0x20, "Outlet" },
+    { 0x84, 0x21, "OutletID" },
+    { 0x84, 0x22, "Gang" },
+    { 0x84, 0x24, "PowerSummary" },
+    { 0x84, 0x25, "PowerSummaryID" },
+    { 0x84, 0x30, "Voltage" },
+    { 0x84, 0x31, "Current" },
+    { 0x84, 0x32, "Frequency" },
+    { 0x84, 0x33, "ApparentPower" },
+    { 0x84, 0x35, "PercentLoad" },
+    { 0x84, 0x40, "ConfigVoltage" },
+    { 0x84, 0x41, "ConfigCurrent" },
+    { 0x84, 0x43, "ConfigApparentPower" },
+    { 0x84, 0x53, "LowVoltageTransfer" },
+    { 0x84, 0x54, "HighVoltageTransfer" },
+    { 0x84, 0x56, "DelayBeforeStartup" },
+    { 0x84, 0x57, "DelayBeforeShutdown" },
+    { 0x84, 0x58, "Test" },
+    { 0x84, 0x5a, "AudibleAlarmControl" },
+    { 0x84, 0x60, "Present" },
+    { 0x84, 0x61, "Good" },
+    { 0x84, 0x62, "InternalFailure" },
+    { 0x84, 0x65, "Overload" },
+    { 0x84, 0x66, "OverCharged" },
+    { 0x84, 0x67, "OverTemperature" },
+    { 0x84, 0x68, "ShutdownRequested" },
+    { 0x84, 0x69, "ShutdownImminent" },
+    { 0x84, 0x6b, "SwitchOn/Off" },
+    { 0x84, 0x6c, "Switchable" },
+    { 0x84, 0x6d, "Used" },
+    { 0x84, 0x6e, "Boost" },
+    { 0x84, 0x73, "CommunicationLost" },
+    { 0x84, 0xfd, "iManufacturer" },
+    { 0x84, 0xfe, "iProduct" },
+    { 0x84, 0xff, "iSerialNumber" },
+  { 0x85, 0, "Battery System" },
+    { 0x85, 0x01, "SMBBatteryMode" },
+    { 0x85, 0x02, "SMBBatteryStatus" },
+    { 0x85, 0x03, "SMBAlarmWarning" },
+    { 0x85, 0x04, "SMBChargerMode" },
+    { 0x85, 0x05, "SMBChargerStatus" },
+    { 0x85, 0x06, "SMBChargerSpecInfo" },
+    { 0x85, 0x07, "SMBSelectorState" },
+    { 0x85, 0x08, "SMBSelectorPresets" },
+    { 0x85, 0x09, "SMBSelectorInfo" },
+    { 0x85, 0x29, "RemainingCapacityLimit" },
+    { 0x85, 0x2c, "CapacityMode" },
+    { 0x85, 0x42, "BelowRemainingCapacityLimit" },
+    { 0x85, 0x44, "Charging" },
+    { 0x85, 0x45, "Discharging" },
+    { 0x85, 0x4b, "NeedReplacement" },
+    { 0x85, 0x66, "RemainingCapacity" },
+    { 0x85, 0x68, "RunTimeToEmpty" },
+    { 0x85, 0x6a, "AverageTimeToFull" },
+    { 0x85, 0x83, "DesignCapacity" },
+    { 0x85, 0x85, "ManufacturerDate" },
+    { 0x85, 0x89, "iDeviceChemistry" },
+    { 0x85, 0x8b, "Rechargable" },
+    { 0x85, 0x8f, "iOEMInformation" },
+    { 0x85, 0x8d, "CapacityGranularity1" },
+    { 0x85, 0xd0, "ACPresent" },
+  /* pages 0xff00 to 0xffff are vendor-specific */
+  { 0xffff, 0, "Vendor-specific-FF" },
+  { 0, 0, NULL }
+};
+
+static void resolv_usage_page(unsigned page) {
+       const struct hid_usage_entry *p;
+
+       for (p = hid_usage_table; p->description; p++)
+               if (p->page == page) {
+                       printk("%s", p->description);
+                       return;
+               }
+       printk("%04x", page);
+}
+
+void hid_resolv_usage(unsigned usage) {
+       const struct hid_usage_entry *p;
+
+       resolv_usage_page(usage >> 16);
+       printk(".");
+       for (p = hid_usage_table; p->description; p++)
+               if (p->page == (usage >> 16)) {
+                       for(++p; p->description && p->usage != 0; p++)
+                               if (p->usage == (usage & 0xffff)) {
+                                       printk("%s", p->description);
+                                       return;
+                               }
+                       break;
+               }
+       printk("%04x", usage & 0xffff);
+}
+EXPORT_SYMBOL_GPL(hid_resolv_usage);
+
+__inline__ static void tab(int n) {
+       while (n--) printk(" ");
+}
+
+void hid_dump_field(struct hid_field *field, int n) {
+       int j;
+
+       if (field->physical) {
+               tab(n);
+               printk("Physical(");
+               hid_resolv_usage(field->physical); printk(")\n");
+       }
+       if (field->logical) {
+               tab(n);
+               printk("Logical(");
+               hid_resolv_usage(field->logical); printk(")\n");
+       }
+       tab(n); printk("Usage(%d)\n", field->maxusage);
+       for (j = 0; j < field->maxusage; j++) {
+               tab(n+2); hid_resolv_usage(field->usage[j].hid); printk("\n");
+       }
+       if (field->logical_minimum != field->logical_maximum) {
+               tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum);
+               tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum);
+       }
+       if (field->physical_minimum != field->physical_maximum) {
+               tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum);
+               tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum);
+       }
+       if (field->unit_exponent) {
+               tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
+       }
+       if (field->unit) {
+               char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
+               char *units[5][8] = {
+                       { "None", "None", "None", "None", "None", "None", "None", "None" },
+                       { "None", "Centimeter", "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
+                       { "None", "Radians",    "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
+                       { "None", "Inch",       "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" },
+                       { "None", "Degrees",    "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }
+               };
+
+               int i;
+               int sys;
+                __u32 data = field->unit;
+
+               /* First nibble tells us which system we're in. */
+               sys = data & 0xf;
+               data >>= 4;
+
+               if(sys > 4) {
+                       tab(n); printk("Unit(Invalid)\n");
+               }
+               else {
+                       int earlier_unit = 0;
+
+                       tab(n); printk("Unit(%s : ", systems[sys]);
+
+                       for (i=1 ; i<sizeof(__u32)*2 ; i++) {
+                               char nibble = data & 0xf;
+                               data >>= 4;
+                               if (nibble != 0) {
+                                       if(earlier_unit++ > 0)
+                                               printk("*");
+                                       printk("%s", units[sys][i]);
+                                       if(nibble != 1) {
+                                               /* This is a _signed_ nibble(!) */
+
+                                               int val = nibble & 0x7;
+                                               if(nibble & 0x08)
+                                                       val = -((0x7 & ~val) +1);
+                                               printk("^%d", val);
+                                       }
+                               }
+                       }
+                       printk(")\n");
+               }
+       }
+       tab(n); printk("Report Size(%u)\n", field->report_size);
+       tab(n); printk("Report Count(%u)\n", field->report_count);
+       tab(n); printk("Report Offset(%u)\n", field->report_offset);
+
+       tab(n); printk("Flags( ");
+       j = field->flags;
+       printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : "");
+       printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array ");
+       printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
+       printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
+       printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
+       printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : "");
+       printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
+       printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
+       printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
+       printk(")\n");
+}
+EXPORT_SYMBOL_GPL(hid_dump_field);
+
+void hid_dump_device(struct hid_device *device) {
+       struct hid_report_enum *report_enum;
+       struct hid_report *report;
+       struct list_head *list;
+       unsigned i,k;
+       static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
+
+       for (i = 0; i < HID_REPORT_TYPES; i++) {
+               report_enum = device->report_enum + i;
+               list = report_enum->report_list.next;
+               while (list != &report_enum->report_list) {
+                       report = (struct hid_report *) list;
+                       tab(2);
+                       printk("%s", table[i]);
+                       if (report->id)
+                               printk("(%d)", report->id);
+                       printk("[%s]", table[report->type]);
+                       printk("\n");
+                       for (k = 0; k < report->maxfield; k++) {
+                               tab(4);
+                               printk("Field(%d)\n", k);
+                               hid_dump_field(report->field[k], 6);
+                       }
+                       list = list->next;
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(hid_dump_device);
+
+void hid_dump_input(struct hid_usage *usage, __s32 value) {
+       printk("hid-debug: input ");
+       hid_resolv_usage(usage->hid);
+       printk(" = %d\n", value);
+}
+EXPORT_SYMBOL_GPL(hid_dump_input);
+
+static char *events[EV_MAX + 1] = {
+       [EV_SYN] = "Sync",                      [EV_KEY] = "Key",
+       [EV_REL] = "Relative",                  [EV_ABS] = "Absolute",
+       [EV_MSC] = "Misc",                      [EV_LED] = "LED",
+       [EV_SND] = "Sound",                     [EV_REP] = "Repeat",
+       [EV_FF] = "ForceFeedback",              [EV_PWR] = "Power",
+       [EV_FF_STATUS] = "ForceFeedbackStatus",
+};
+
+static char *syncs[2] = {
+       [SYN_REPORT] = "Report",                [SYN_CONFIG] = "Config",
+};
+static char *keys[KEY_MAX + 1] = {
+       [KEY_RESERVED] = "Reserved",            [KEY_ESC] = "Esc",
+       [KEY_1] = "1",                          [KEY_2] = "2",
+       [KEY_3] = "3",                          [KEY_4] = "4",
+       [KEY_5] = "5",                          [KEY_6] = "6",
+       [KEY_7] = "7",                          [KEY_8] = "8",
+       [KEY_9] = "9",                          [KEY_0] = "0",
+       [KEY_MINUS] = "Minus",                  [KEY_EQUAL] = "Equal",
+       [KEY_BACKSPACE] = "Backspace",          [KEY_TAB] = "Tab",
+       [KEY_Q] = "Q",                          [KEY_W] = "W",
+       [KEY_E] = "E",                          [KEY_R] = "R",
+       [KEY_T] = "T",                          [KEY_Y] = "Y",
+       [KEY_U] = "U",                          [KEY_I] = "I",
+       [KEY_O] = "O",                          [KEY_P] = "P",
+       [KEY_LEFTBRACE] = "LeftBrace",          [KEY_RIGHTBRACE] = "RightBrace",
+       [KEY_ENTER] = "Enter",                  [KEY_LEFTCTRL] = "LeftControl",
+       [KEY_A] = "A",                          [KEY_S] = "S",
+       [KEY_D] = "D",                          [KEY_F] = "F",
+       [KEY_G] = "G",                          [KEY_H] = "H",
+       [KEY_J] = "J",                          [KEY_K] = "K",
+       [KEY_L] = "L",                          [KEY_SEMICOLON] = "Semicolon",
+       [KEY_APOSTROPHE] = "Apostrophe",        [KEY_GRAVE] = "Grave",
+       [KEY_LEFTSHIFT] = "LeftShift",          [KEY_BACKSLASH] = "BackSlash",
+       [KEY_Z] = "Z",                          [KEY_X] = "X",
+       [KEY_C] = "C",                          [KEY_V] = "V",
+       [KEY_B] = "B",                          [KEY_N] = "N",
+       [KEY_M] = "M",                          [KEY_COMMA] = "Comma",
+       [KEY_DOT] = "Dot",                      [KEY_SLASH] = "Slash",
+       [KEY_RIGHTSHIFT] = "RightShift",        [KEY_KPASTERISK] = "KPAsterisk",
+       [KEY_LEFTALT] = "LeftAlt",              [KEY_SPACE] = "Space",
+       [KEY_CAPSLOCK] = "CapsLock",            [KEY_F1] = "F1",
+       [KEY_F2] = "F2",                        [KEY_F3] = "F3",
+       [KEY_F4] = "F4",                        [KEY_F5] = "F5",
+       [KEY_F6] = "F6",                        [KEY_F7] = "F7",
+       [KEY_F8] = "F8",                        [KEY_F9] = "F9",
+       [KEY_F10] = "F10",                      [KEY_NUMLOCK] = "NumLock",
+       [KEY_SCROLLLOCK] = "ScrollLock",        [KEY_KP7] = "KP7",
+       [KEY_KP8] = "KP8",                      [KEY_KP9] = "KP9",
+       [KEY_KPMINUS] = "KPMinus",              [KEY_KP4] = "KP4",
+       [KEY_KP5] = "KP5",                      [KEY_KP6] = "KP6",
+       [KEY_KPPLUS] = "KPPlus",                [KEY_KP1] = "KP1",
+       [KEY_KP2] = "KP2",                      [KEY_KP3] = "KP3",
+       [KEY_KP0] = "KP0",                      [KEY_KPDOT] = "KPDot",
+       [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd",
+       [KEY_F11] = "F11",                      [KEY_F12] = "F12",
+       [KEY_RO] = "RO",                        [KEY_KATAKANA] = "Katakana",
+       [KEY_HIRAGANA] = "HIRAGANA",            [KEY_HENKAN] = "Henkan",
+       [KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan",
+       [KEY_KPJPCOMMA] = "KPJpComma",          [KEY_KPENTER] = "KPEnter",
+       [KEY_RIGHTCTRL] = "RightCtrl",          [KEY_KPSLASH] = "KPSlash",
+       [KEY_SYSRQ] = "SysRq",                  [KEY_RIGHTALT] = "RightAlt",
+       [KEY_LINEFEED] = "LineFeed",            [KEY_HOME] = "Home",
+       [KEY_UP] = "Up",                        [KEY_PAGEUP] = "PageUp",
+       [KEY_LEFT] = "Left",                    [KEY_RIGHT] = "Right",
+       [KEY_END] = "End",                      [KEY_DOWN] = "Down",
+       [KEY_PAGEDOWN] = "PageDown",            [KEY_INSERT] = "Insert",
+       [KEY_DELETE] = "Delete",                [KEY_MACRO] = "Macro",
+       [KEY_MUTE] = "Mute",                    [KEY_VOLUMEDOWN] = "VolumeDown",
+       [KEY_VOLUMEUP] = "VolumeUp",            [KEY_POWER] = "Power",
+       [KEY_KPEQUAL] = "KPEqual",              [KEY_KPPLUSMINUS] = "KPPlusMinus",
+       [KEY_PAUSE] = "Pause",                  [KEY_KPCOMMA] = "KPComma",
+       [KEY_HANGUEL] = "Hangeul",              [KEY_HANJA] = "Hanja",
+       [KEY_YEN] = "Yen",                      [KEY_LEFTMETA] = "LeftMeta",
+       [KEY_RIGHTMETA] = "RightMeta",          [KEY_COMPOSE] = "Compose",
+       [KEY_STOP] = "Stop",                    [KEY_AGAIN] = "Again",
+       [KEY_PROPS] = "Props",                  [KEY_UNDO] = "Undo",
+       [KEY_FRONT] = "Front",                  [KEY_COPY] = "Copy",
+       [KEY_OPEN] = "Open",                    [KEY_PASTE] = "Paste",
+       [KEY_FIND] = "Find",                    [KEY_CUT] = "Cut",
+       [KEY_HELP] = "Help",                    [KEY_MENU] = "Menu",
+       [KEY_CALC] = "Calc",                    [KEY_SETUP] = "Setup",
+       [KEY_SLEEP] = "Sleep",                  [KEY_WAKEUP] = "WakeUp",
+       [KEY_FILE] = "File",                    [KEY_SENDFILE] = "SendFile",
+       [KEY_DELETEFILE] = "DeleteFile",        [KEY_XFER] = "X-fer",
+       [KEY_PROG1] = "Prog1",                  [KEY_PROG2] = "Prog2",
+       [KEY_WWW] = "WWW",                      [KEY_MSDOS] = "MSDOS",
+       [KEY_COFFEE] = "Coffee",                [KEY_DIRECTION] = "Direction",
+       [KEY_CYCLEWINDOWS] = "CycleWindows",    [KEY_MAIL] = "Mail",
+       [KEY_BOOKMARKS] = "Bookmarks",          [KEY_COMPUTER] = "Computer",
+       [KEY_BACK] = "Back",                    [KEY_FORWARD] = "Forward",
+       [KEY_CLOSECD] = "CloseCD",              [KEY_EJECTCD] = "EjectCD",
+       [KEY_EJECTCLOSECD] = "EjectCloseCD",    [KEY_NEXTSONG] = "NextSong",
+       [KEY_PLAYPAUSE] = "PlayPause",          [KEY_PREVIOUSSONG] = "PreviousSong",
+       [KEY_STOPCD] = "StopCD",                [KEY_RECORD] = "Record",
+       [KEY_REWIND] = "Rewind",                [KEY_PHONE] = "Phone",
+       [KEY_ISO] = "ISOKey",                   [KEY_CONFIG] = "Config",
+       [KEY_HOMEPAGE] = "HomePage",            [KEY_REFRESH] = "Refresh",
+       [KEY_EXIT] = "Exit",                    [KEY_MOVE] = "Move",
+       [KEY_EDIT] = "Edit",                    [KEY_SCROLLUP] = "ScrollUp",
+       [KEY_SCROLLDOWN] = "ScrollDown",        [KEY_KPLEFTPAREN] = "KPLeftParenthesis",
+       [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New",
+       [KEY_REDO] = "Redo",                    [KEY_F13] = "F13",
+       [KEY_F14] = "F14",                      [KEY_F15] = "F15",
+       [KEY_F16] = "F16",                      [KEY_F17] = "F17",
+       [KEY_F18] = "F18",                      [KEY_F19] = "F19",
+       [KEY_F20] = "F20",                      [KEY_F21] = "F21",
+       [KEY_F22] = "F22",                      [KEY_F23] = "F23",
+       [KEY_F24] = "F24",                      [KEY_PLAYCD] = "PlayCD",
+       [KEY_PAUSECD] = "PauseCD",              [KEY_PROG3] = "Prog3",
+       [KEY_PROG4] = "Prog4",                  [KEY_SUSPEND] = "Suspend",
+       [KEY_CLOSE] = "Close",                  [KEY_PLAY] = "Play",
+       [KEY_FASTFORWARD] = "FastForward",      [KEY_BASSBOOST] = "BassBoost",
+       [KEY_PRINT] = "Print",                  [KEY_HP] = "HP",
+       [KEY_CAMERA] = "Camera",                [KEY_SOUND] = "Sound",
+       [KEY_QUESTION] = "Question",            [KEY_EMAIL] = "Email",
+       [KEY_CHAT] = "Chat",                    [KEY_SEARCH] = "Search",
+       [KEY_CONNECT] = "Connect",              [KEY_FINANCE] = "Finance",
+       [KEY_SPORT] = "Sport",                  [KEY_SHOP] = "Shop",
+       [KEY_ALTERASE] = "AlternateErase",      [KEY_CANCEL] = "Cancel",
+       [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp",
+       [KEY_MEDIA] = "Media",                  [KEY_UNKNOWN] = "Unknown",
+       [BTN_0] = "Btn0",                       [BTN_1] = "Btn1",
+       [BTN_2] = "Btn2",                       [BTN_3] = "Btn3",
+       [BTN_4] = "Btn4",                       [BTN_5] = "Btn5",
+       [BTN_6] = "Btn6",                       [BTN_7] = "Btn7",
+       [BTN_8] = "Btn8",                       [BTN_9] = "Btn9",
+       [BTN_LEFT] = "LeftBtn",                 [BTN_RIGHT] = "RightBtn",
+       [BTN_MIDDLE] = "MiddleBtn",             [BTN_SIDE] = "SideBtn",
+       [BTN_EXTRA] = "ExtraBtn",               [BTN_FORWARD] = "ForwardBtn",
+       [BTN_BACK] = "BackBtn",                 [BTN_TASK] = "TaskBtn",
+       [BTN_TRIGGER] = "Trigger",              [BTN_THUMB] = "ThumbBtn",
+       [BTN_THUMB2] = "ThumbBtn2",             [BTN_TOP] = "TopBtn",
+       [BTN_TOP2] = "TopBtn2",                 [BTN_PINKIE] = "PinkieBtn",
+       [BTN_BASE] = "BaseBtn",                 [BTN_BASE2] = "BaseBtn2",
+       [BTN_BASE3] = "BaseBtn3",               [BTN_BASE4] = "BaseBtn4",
+       [BTN_BASE5] = "BaseBtn5",               [BTN_BASE6] = "BaseBtn6",
+       [BTN_DEAD] = "BtnDead",                 [BTN_A] = "BtnA",
+       [BTN_B] = "BtnB",                       [BTN_C] = "BtnC",
+       [BTN_X] = "BtnX",                       [BTN_Y] = "BtnY",
+       [BTN_Z] = "BtnZ",                       [BTN_TL] = "BtnTL",
+       [BTN_TR] = "BtnTR",                     [BTN_TL2] = "BtnTL2",
+       [BTN_TR2] = "BtnTR2",                   [BTN_SELECT] = "BtnSelect",
+       [BTN_START] = "BtnStart",               [BTN_MODE] = "BtnMode",
+       [BTN_THUMBL] = "BtnThumbL",             [BTN_THUMBR] = "BtnThumbR",
+       [BTN_TOOL_PEN] = "ToolPen",             [BTN_TOOL_RUBBER] = "ToolRubber",
+       [BTN_TOOL_BRUSH] = "ToolBrush",         [BTN_TOOL_PENCIL] = "ToolPencil",
+       [BTN_TOOL_AIRBRUSH] = "ToolAirbrush",   [BTN_TOOL_FINGER] = "ToolFinger",
+       [BTN_TOOL_MOUSE] = "ToolMouse",         [BTN_TOOL_LENS] = "ToolLens",
+       [BTN_TOUCH] = "Touch",                  [BTN_STYLUS] = "Stylus",
+       [BTN_STYLUS2] = "Stylus2",              [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap",
+       [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn",
+       [BTN_GEAR_UP] = "Gear up",              [KEY_OK] = "Ok",
+       [KEY_SELECT] = "Select",                [KEY_GOTO] = "Goto",
+       [KEY_CLEAR] = "Clear",                  [KEY_POWER2] = "Power2",
+       [KEY_OPTION] = "Option",                [KEY_INFO] = "Info",
+       [KEY_TIME] = "Time",                    [KEY_VENDOR] = "Vendor",
+       [KEY_ARCHIVE] = "Archive",              [KEY_PROGRAM] = "Program",
+       [KEY_CHANNEL] = "Channel",              [KEY_FAVORITES] = "Favorites",
+       [KEY_EPG] = "EPG",                      [KEY_PVR] = "PVR",
+       [KEY_MHP] = "MHP",                      [KEY_LANGUAGE] = "Language",
+       [KEY_TITLE] = "Title",                  [KEY_SUBTITLE] = "Subtitle",
+       [KEY_ANGLE] = "Angle",                  [KEY_ZOOM] = "Zoom",
+       [KEY_MODE] = "Mode",                    [KEY_KEYBOARD] = "Keyboard",
+       [KEY_SCREEN] = "Screen",                [KEY_PC] = "PC",
+       [KEY_TV] = "TV",                        [KEY_TV2] = "TV2",
+       [KEY_VCR] = "VCR",                      [KEY_VCR2] = "VCR2",
+       [KEY_SAT] = "Sat",                      [KEY_SAT2] = "Sat2",
+       [KEY_CD] = "CD",                        [KEY_TAPE] = "Tape",
+       [KEY_RADIO] = "Radio",                  [KEY_TUNER] = "Tuner",
+       [KEY_PLAYER] = "Player",                [KEY_TEXT] = "Text",
+       [KEY_DVD] = "DVD",                      [KEY_AUX] = "Aux",
+       [KEY_MP3] = "MP3",                      [KEY_AUDIO] = "Audio",
+       [KEY_VIDEO] = "Video",                  [KEY_DIRECTORY] = "Directory",
+       [KEY_LIST] = "List",                    [KEY_MEMO] = "Memo",
+       [KEY_CALENDAR] = "Calendar",            [KEY_RED] = "Red",
+       [KEY_GREEN] = "Green",                  [KEY_YELLOW] = "Yellow",
+       [KEY_BLUE] = "Blue",                    [KEY_CHANNELUP] = "ChannelUp",
+       [KEY_CHANNELDOWN] = "ChannelDown",      [KEY_FIRST] = "First",
+       [KEY_LAST] = "Last",                    [KEY_AB] = "AB",
+       [KEY_NEXT] = "Next",                    [KEY_RESTART] = "Restart",
+       [KEY_SLOW] = "Slow",                    [KEY_SHUFFLE] = "Shuffle",
+       [KEY_BREAK] = "Break",                  [KEY_PREVIOUS] = "Previous",
+       [KEY_DIGITS] = "Digits",                [KEY_TEEN] = "TEEN",
+       [KEY_TWEN] = "TWEN",                    [KEY_DEL_EOL] = "DeleteEOL",
+       [KEY_DEL_EOS] = "DeleteEOS",            [KEY_INS_LINE] = "InsertLine",
+       [KEY_DEL_LINE] = "DeleteLine",
+       [KEY_SEND] = "Send",                    [KEY_REPLY] = "Reply",
+       [KEY_FORWARDMAIL] = "ForwardMail",      [KEY_SAVE] = "Save",
+       [KEY_DOCUMENTS] = "Documents",
+       [KEY_FN] = "Fn",                        [KEY_FN_ESC] = "Fn+ESC",
+       [KEY_FN_1] = "Fn+1",                    [KEY_FN_2] = "Fn+2",
+       [KEY_FN_B] = "Fn+B",                    [KEY_FN_D] = "Fn+D",
+       [KEY_FN_E] = "Fn+E",                    [KEY_FN_F] = "Fn+F",
+       [KEY_FN_S] = "Fn+S",
+       [KEY_FN_F1] = "Fn+F1",                  [KEY_FN_F2] = "Fn+F2",
+       [KEY_FN_F3] = "Fn+F3",                  [KEY_FN_F4] = "Fn+F4",
+       [KEY_FN_F5] = "Fn+F5",                  [KEY_FN_F6] = "Fn+F6",
+       [KEY_FN_F7] = "Fn+F7",                  [KEY_FN_F8] = "Fn+F8",
+       [KEY_FN_F9] = "Fn+F9",                  [KEY_FN_F10] = "Fn+F10",
+       [KEY_FN_F11] = "Fn+F11",                [KEY_FN_F12] = "Fn+F12",
+       [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle",
+       [KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
+       [KEY_KBDILLUMUP] = "KbdIlluminationUp",
+       [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
+};
+
+static char *relatives[REL_MAX + 1] = {
+       [REL_X] = "X",                  [REL_Y] = "Y",
+       [REL_Z] = "Z",                  [REL_RX] = "Rx",
+       [REL_RY] = "Ry",                [REL_RZ] = "Rz",
+       [REL_HWHEEL] = "HWheel",        [REL_DIAL] = "Dial",
+       [REL_WHEEL] = "Wheel",          [REL_MISC] = "Misc",
+};
+
+static char *absolutes[ABS_MAX + 1] = {
+       [ABS_X] = "X",                  [ABS_Y] = "Y",
+       [ABS_Z] = "Z",                  [ABS_RX] = "Rx",
+       [ABS_RY] = "Ry",                [ABS_RZ] = "Rz",
+       [ABS_THROTTLE] = "Throttle",    [ABS_RUDDER] = "Rudder",
+       [ABS_WHEEL] = "Wheel",          [ABS_GAS] = "Gas",
+       [ABS_BRAKE] = "Brake",          [ABS_HAT0X] = "Hat0X",
+       [ABS_HAT0Y] = "Hat0Y",          [ABS_HAT1X] = "Hat1X",
+       [ABS_HAT1Y] = "Hat1Y",          [ABS_HAT2X] = "Hat2X",
+       [ABS_HAT2Y] = "Hat2Y",          [ABS_HAT3X] = "Hat3X",
+       [ABS_HAT3Y] = "Hat 3Y",         [ABS_PRESSURE] = "Pressure",
+       [ABS_DISTANCE] = "Distance",    [ABS_TILT_X] = "XTilt",
+       [ABS_TILT_Y] = "YTilt",         [ABS_TOOL_WIDTH] = "Tool Width",
+       [ABS_VOLUME] = "Volume",        [ABS_MISC] = "Misc",
+};
+
+static char *misc[MSC_MAX + 1] = {
+       [MSC_SERIAL] = "Serial",        [MSC_PULSELED] = "Pulseled",
+       [MSC_GESTURE] = "Gesture",      [MSC_RAW] = "RawData"
+};
+
+static char *leds[LED_MAX + 1] = {
+       [LED_NUML] = "NumLock",         [LED_CAPSL] = "CapsLock",
+       [LED_SCROLLL] = "ScrollLock",   [LED_COMPOSE] = "Compose",
+       [LED_KANA] = "Kana",            [LED_SLEEP] = "Sleep",
+       [LED_SUSPEND] = "Suspend",      [LED_MUTE] = "Mute",
+       [LED_MISC] = "Misc",
+};
+
+static char *repeats[REP_MAX + 1] = {
+       [REP_DELAY] = "Delay",          [REP_PERIOD] = "Period"
+};
+
+static char *sounds[SND_MAX + 1] = {
+       [SND_CLICK] = "Click",          [SND_BELL] = "Bell",
+       [SND_TONE] = "Tone"
+};
+
+static char **names[EV_MAX + 1] = {
+       [EV_SYN] = syncs,                       [EV_KEY] = keys,
+       [EV_REL] = relatives,                   [EV_ABS] = absolutes,
+       [EV_MSC] = misc,                        [EV_LED] = leds,
+       [EV_SND] = sounds,                      [EV_REP] = repeats,
+};
+
+void hid_resolv_event(__u8 type, __u16 code) {
+
+       printk("%s.%s", events[type] ? events[type] : "?",
+               names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
+}
+EXPORT_SYMBOL_GPL(hid_resolv_event);
+
index c7a6833..25d180a 100644 (file)
@@ -31,9 +31,8 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 
-#undef DEBUG
-
 #include <linux/hid.h>
+#include <linux/hid-debug.h>
 
 static int hid_pb_fnmode = 1;
 module_param_named(pb_fnmode, hid_pb_fnmode, int, 0644);
@@ -252,9 +251,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
 
        field->hidinput = hidinput;
 
-#ifdef DEBUG
+#ifdef CONFIG_HID_DEBUG
        printk(KERN_DEBUG "Mapping: ");
-       resolv_usage(usage->hid);
+       hid_resolv_usage(usage->hid);
        printk(" ---> ");
 #endif
 
@@ -682,14 +681,14 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                        field->dpad = usage->code;
        }
 
-#ifdef DEBUG
-       resolv_event(usage->type, usage->code);
+       hid_resolv_event(usage->type, usage->code);
+#ifdef CONFIG_HID_DEBUG
        printk("\n");
 #endif
        return;
 
 ignore:
-#ifdef DEBUG
+#ifdef CONFIG_HID_DEBUG
        printk("IGNORED\n");
 #endif
        return;
@@ -804,6 +803,18 @@ int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int
 }
 EXPORT_SYMBOL_GPL(hidinput_find_field);
 
+static int hidinput_open(struct input_dev *dev)
+{
+       struct hid_device *hid = dev->private;
+       return hid->hid_open(hid);
+}
+
+static void hidinput_close(struct input_dev *dev)
+{
+       struct hid_device *hid = dev->private;
+       hid->hid_close(hid);
+}
+
 /*
  * Register the input device; print a message.
  * Configure the input layer interface
@@ -816,6 +827,7 @@ int hidinput_connect(struct hid_device *hid)
        struct hid_input *hidinput = NULL;
        struct input_dev *input_dev;
        int i, j, k;
+       int max_report_type = HID_OUTPUT_REPORT;
 
        INIT_LIST_HEAD(&hid->inputs);
 
@@ -828,7 +840,10 @@ int hidinput_connect(struct hid_device *hid)
        if (i == hid->maxcollection)
                return -1;
 
-       for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++)
+       if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
+               max_report_type = HID_INPUT_REPORT;
+
+       for (k = HID_INPUT_REPORT; k <= max_report_type; k++)
                list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
 
                        if (!report->maxfield)
@@ -846,8 +861,8 @@ int hidinput_connect(struct hid_device *hid)
 
                                input_dev->private = hid;
                                input_dev->event = hid->hidinput_input_event;
-                               input_dev->open = hid->hidinput_open;
-                               input_dev->close = hid->hidinput_close;
+                               input_dev->open = hidinput_open;
+                               input_dev->close = hidinput_close;
 
                                input_dev->name = hid->name;
                                input_dev->phys = hid->phys;
index ccdf3e9..9fafadb 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb.h>
 #include <linux/usb/otg.h>
index 3f82805..ec03341 100644 (file)
@@ -167,6 +167,13 @@ config BLK_DEV_IDECS
          Support for Compact Flash cards, outboard IDE disks, tape drives,
          and CD-ROM drives connected through a PCMCIA card.
 
+config BLK_DEV_DELKIN
+       tristate "Cardbus IDE support (Delkin/ASKA/Workbit)"
+       depends on CARDBUS && PCI
+       help
+         Support for Delkin, ASKA, and Workbit Cardbus CompactFlash
+         Adapters.  This may also work for similar SD and XD adapters.
+
 config BLK_DEV_IDECD
        tristate "Include IDE/ATAPI CDROM support"
        ---help---
@@ -264,6 +271,13 @@ config BLK_DEV_IDESCSI
          If both this SCSI emulation and native ATAPI support are compiled
          into the kernel, the native support will be used.
 
+config BLK_DEV_IDEACPI
+       bool "IDE ACPI support"
+       depends on ACPI
+       ---help---
+         Implement ACPI support for generic IDE devices. On modern
+         machines ACPI support is required to properly handle ACPI S3 states.
+
 config IDE_TASK_IOCTL
        bool "IDE Taskfile Access"
        help
@@ -606,6 +620,11 @@ config BLK_DEV_PIIX
          the kernel to change PIO, DMA and UDMA speeds and to configure
          the chip to optimum performance.
 
+config BLK_DEV_IT8213
+       tristate "IT8213 IDE support"
+       help
+        This driver adds support for the ITE 8213 IDE controller.
+
 config BLK_DEV_IT821X
        tristate "IT821X IDE support"
        help
@@ -742,6 +761,11 @@ config BLK_DEV_VIA82CXXX
          This allows the kernel to change PIO, DMA and UDMA speeds and to
          configure the chip to optimum performance.
 
+config BLK_DEV_TC86C001
+       tristate "Toshiba TC86C001 support"
+       help
+       This driver adds support for Toshiba TC86C001 GOKU-S chip.
+
 endif
 
 config BLK_DEV_IDE_PMAC
index 569fae7..d9f029e 100644 (file)
@@ -22,6 +22,7 @@ ide-core-$(CONFIG_BLK_DEV_IDEPCI)     += setup-pci.o
 ide-core-$(CONFIG_BLK_DEV_IDEDMA)      += ide-dma.o
 ide-core-$(CONFIG_PROC_FS)             += ide-proc.o
 ide-core-$(CONFIG_BLK_DEV_IDEPNP)      += ide-pnp.o
+ide-core-$(CONFIG_BLK_DEV_IDEACPI)     += ide-acpi.o
 
 # built-in only drivers from arm/
 ide-core-$(CONFIG_IDE_ARM)             += arm/ide_arm.o
diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c
new file mode 100644 (file)
index 0000000..17aea65
--- /dev/null
@@ -0,0 +1,697 @@
+/*
+ * ide-acpi.c
+ * Provides ACPI support for IDE drives.
+ *
+ * Copyright (C) 2005 Intel Corp.
+ * Copyright (C) 2005 Randy Dunlap
+ * Copyright (C) 2006 SUSE Linux Products GmbH
+ * Copyright (C) 2006 Hannes Reinecke
+ */
+
+#include <linux/ata.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <acpi/acpi.h>
+#include <linux/ide.h>
+#include <linux/pci.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acnames.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acexcep.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+
+#define REGS_PER_GTF           7
+struct taskfile_array {
+       u8      tfa[REGS_PER_GTF];      /* regs. 0x1f1 - 0x1f7 */
+};
+
+struct GTM_buffer {
+       u32     PIO_speed0;
+       u32     DMA_speed0;
+       u32     PIO_speed1;
+       u32     DMA_speed1;
+       u32     GTM_flags;
+};
+
+struct ide_acpi_drive_link {
+       ide_drive_t     *drive;
+       acpi_handle      obj_handle;
+       u8               idbuff[512];
+};
+
+struct ide_acpi_hwif_link {
+       ide_hwif_t                      *hwif;
+       acpi_handle                      obj_handle;
+       struct GTM_buffer                gtm;
+       struct ide_acpi_drive_link       master;
+       struct ide_acpi_drive_link       slave;
+};
+
+#undef DEBUGGING
+/* note: adds function name and KERN_DEBUG */
+#ifdef DEBUGGING
+#define DEBPRINT(fmt, args...) \
+               printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DEBPRINT(fmt, args...) do {} while (0)
+#endif /* DEBUGGING */
+
+extern int ide_noacpi;
+extern int ide_noacpitfs;
+extern int ide_noacpionboot;
+
+/**
+ * ide_get_dev_handle - finds acpi_handle and PCI device.function
+ * @dev: device to locate
+ * @handle: returned acpi_handle for @dev
+ * @pcidevfn: return PCI device.func for @dev
+ *
+ * Returns the ACPI object handle to the corresponding PCI device.
+ *
+ * Returns 0 on success, <0 on error.
+ */
+static int ide_get_dev_handle(struct device *dev, acpi_handle *handle,
+                              acpi_integer *pcidevfn)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       unsigned int bus, devnum, func;
+       acpi_integer addr;
+       acpi_handle dev_handle;
+       struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER,
+                                       .pointer = NULL};
+       acpi_status status;
+       struct acpi_device_info *dinfo = NULL;
+       int ret = -ENODEV;
+
+       bus = pdev->bus->number;
+       devnum = PCI_SLOT(pdev->devfn);
+       func = PCI_FUNC(pdev->devfn);
+       /* ACPI _ADR encoding for PCI bus: */
+       addr = (acpi_integer)(devnum << 16 | func);
+
+       DEBPRINT("ENTER: pci %02x:%02x.%01x\n", bus, devnum, func);
+
+       dev_handle = DEVICE_ACPI_HANDLE(dev);
+       if (!dev_handle) {
+               DEBPRINT("no acpi handle for device\n");
+               goto err;
+       }
+
+       status = acpi_get_object_info(dev_handle, &buffer);
+       if (ACPI_FAILURE(status)) {
+               DEBPRINT("get_object_info for device failed\n");
+               goto err;
+       }
+       dinfo = buffer.pointer;
+       if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
+           dinfo->address == addr) {
+               *pcidevfn = addr;
+               *handle = dev_handle;
+       } else {
+               DEBPRINT("get_object_info for device has wrong "
+                       " address: %llu, should be %u\n",
+                       dinfo ? (unsigned long long)dinfo->address : -1ULL,
+                       (unsigned int)addr);
+               goto err;
+       }
+
+       DEBPRINT("for dev=0x%x.%x, addr=0x%llx, *handle=0x%p\n",
+                devnum, func, (unsigned long long)addr, *handle);
+       ret = 0;
+err:
+       kfree(dinfo);
+       return ret;
+}
+
+/**
+ * ide_acpi_hwif_get_handle - Get ACPI object handle for a given hwif
+ * @hwif: device to locate
+ *
+ * Retrieves the object handle for a given hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
+{
+       struct device           *dev = hwif->gendev.parent;
+       acpi_handle             dev_handle;
+       acpi_integer            pcidevfn;
+       acpi_handle             chan_handle;
+       int                     err;
+
+       DEBPRINT("ENTER: device %s\n", hwif->name);
+
+       if (!dev) {
+               DEBPRINT("no PCI device for %s\n", hwif->name);
+               return NULL;
+       }
+
+       err = ide_get_dev_handle(dev, &dev_handle, &pcidevfn);
+       if (err < 0) {
+               DEBPRINT("ide_get_dev_handle failed (%d)\n", err);
+               return NULL;
+       }
+
+       /* get child objects of dev_handle == channel objects,
+        * + _their_ children == drive objects */
+       /* channel is hwif->channel */
+       chan_handle = acpi_get_child(dev_handle, hwif->channel);
+       DEBPRINT("chan adr=%d: handle=0x%p\n",
+                hwif->channel, chan_handle);
+
+       return chan_handle;
+}
+
+/**
+ * ide_acpi_drive_get_handle - Get ACPI object handle for a given drive
+ * @drive: device to locate
+ *
+ * Retrieves the object handle of a given drive. According to the ACPI
+ * spec the drive is a child of the hwif.
+ *
+ * Returns handle on success, 0 on error.
+ */
+static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive)
+{
+       ide_hwif_t      *hwif = HWIF(drive);
+       int              port;
+       acpi_handle      drive_handle;
+
+       if (!hwif->acpidata)
+               return NULL;
+
+       if (!hwif->acpidata->obj_handle)
+               return NULL;
+
+       port = hwif->channel ? drive->dn - 2: drive->dn;
+
+       DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
+                drive->name, hwif->channel, port);
+
+
+       /* TBD: could also check ACPI object VALID bits */
+       drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port);
+       DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle);
+
+       return drive_handle;
+}
+
+/**
+ * do_drive_get_GTF - get the drive bootup default taskfile settings
+ * @drive: the drive for which the taskfile settings should be retrieved
+ * @gtf_length: number of bytes of _GTF data returned at @gtf_address
+ * @gtf_address: buffer containing _GTF taskfile arrays
+ *
+ * The _GTF method has no input parameters.
+ * It returns a variable number of register set values (registers
+ * hex 1F1..1F7, taskfiles).
+ * The <variable number> is not known in advance, so have ACPI-CA
+ * allocate the buffer as needed and return it, then free it later.
+ *
+ * The returned @gtf_length and @gtf_address are only valid if the
+ * function return value is 0.
+ */
+static int do_drive_get_GTF(ide_drive_t *drive,
+                    unsigned int *gtf_length, unsigned long *gtf_address,
+                    unsigned long *obj_loc)
+{
+       acpi_status                     status;
+       struct acpi_buffer              output;
+       union acpi_object               *out_obj;
+       ide_hwif_t                      *hwif = HWIF(drive);
+       struct device                   *dev = hwif->gendev.parent;
+       int                             err = -ENODEV;
+       int                             port;
+
+       *gtf_length = 0;
+       *gtf_address = 0UL;
+       *obj_loc = 0UL;
+
+       if (ide_noacpi)
+               return 0;
+
+       if (!dev) {
+               DEBPRINT("no PCI device for %s\n", hwif->name);
+               goto out;
+       }
+
+       if (!hwif->acpidata) {
+               DEBPRINT("no ACPI data for %s\n", hwif->name);
+               goto out;
+       }
+
+       port = hwif->channel ? drive->dn - 2: drive->dn;
+
+       if (!drive->acpidata) {
+               if (port == 0) {
+                       drive->acpidata = &hwif->acpidata->master;
+                       hwif->acpidata->master.drive = drive;
+               } else {
+                       drive->acpidata = &hwif->acpidata->slave;
+                       hwif->acpidata->slave.drive = drive;
+               }
+       }
+
+       DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
+                hwif->name, dev->bus_id, port, hwif->channel);
+
+       if (!drive->present) {
+               DEBPRINT("%s drive %d:%d not present\n",
+                        hwif->name, hwif->channel, port);
+               goto out;
+       }
+
+       /* Get this drive's _ADR info. if not already known. */
+       if (!drive->acpidata->obj_handle) {
+               drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
+               if (!drive->acpidata->obj_handle) {
+                       DEBPRINT("No ACPI object found for %s\n",
+                                drive->name);
+                       goto out;
+               }
+       }
+
+       /* Setting up output buffer */
+       output.length = ACPI_ALLOCATE_BUFFER;
+       output.pointer = NULL;  /* ACPI-CA sets this; save/free it later */
+
+       /* _GTF has no input parameters */
+       err = -EIO;
+       status = acpi_evaluate_object(drive->acpidata->obj_handle, "_GTF",
+                                     NULL, &output);
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_DEBUG
+                      "%s: Run _GTF error: status = 0x%x\n",
+                      __FUNCTION__, status);
+               goto out;
+       }
+
+       if (!output.length || !output.pointer) {
+               DEBPRINT("Run _GTF: "
+                      "length or ptr is NULL (0x%llx, 0x%p)\n",
+                      (unsigned long long)output.length,
+                      output.pointer);
+               goto out;
+       }
+
+       out_obj = output.pointer;
+       if (out_obj->type != ACPI_TYPE_BUFFER) {
+               DEBPRINT("Run _GTF: error: "
+                      "expected object type of ACPI_TYPE_BUFFER, "
+                      "got 0x%x\n", out_obj->type);
+               err = -ENOENT;
+               kfree(output.pointer);
+               goto out;
+       }
+
+       if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+           out_obj->buffer.length % REGS_PER_GTF) {
+               printk(KERN_ERR
+                      "%s: unexpected GTF length (%d) or addr (0x%p)\n",
+                      __FUNCTION__, out_obj->buffer.length,
+                      out_obj->buffer.pointer);
+               err = -ENOENT;
+               kfree(output.pointer);
+               goto out;
+       }
+
+       *gtf_length = out_obj->buffer.length;
+       *gtf_address = (unsigned long)out_obj->buffer.pointer;
+       *obj_loc = (unsigned long)out_obj;
+       DEBPRINT("returning gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n",
+                *gtf_length, *gtf_address, *obj_loc);
+       err = 0;
+out:
+       return err;
+}
+
+/**
+ * taskfile_load_raw - send taskfile registers to drive
+ * @drive: drive to which output is sent
+ * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
+ *
+ * Outputs IDE taskfile to the drive.
+ */
+static int taskfile_load_raw(ide_drive_t *drive,
+                             const struct taskfile_array *gtf)
+{
+       ide_task_t args;
+       int err = 0;
+
+       DEBPRINT("(0x1f1-1f7): hex: "
+              "%02x %02x %02x %02x %02x %02x %02x\n",
+              gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
+              gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
+
+       memset(&args, 0, sizeof(ide_task_t));
+       args.command_type = IDE_DRIVE_TASK_NO_DATA;
+       args.data_phase   = TASKFILE_IN;
+       args.handler      = &task_no_data_intr;
+
+       /* convert gtf to IDE Taskfile */
+       args.tfRegister[1] = gtf->tfa[0];       /* 0x1f1 */
+       args.tfRegister[2] = gtf->tfa[1];       /* 0x1f2 */
+       args.tfRegister[3] = gtf->tfa[2];       /* 0x1f3 */
+       args.tfRegister[4] = gtf->tfa[3];       /* 0x1f4 */
+       args.tfRegister[5] = gtf->tfa[4];       /* 0x1f5 */
+       args.tfRegister[6] = gtf->tfa[5];       /* 0x1f6 */
+       args.tfRegister[7] = gtf->tfa[6];       /* 0x1f7 */
+
+       if (ide_noacpitfs) {
+               DEBPRINT("_GTF execution disabled\n");
+               return err;
+       }
+
+       err = ide_raw_taskfile(drive, &args, NULL);
+       if (err)
+               printk(KERN_ERR "%s: ide_raw_taskfile failed: %u\n",
+                      __FUNCTION__, err);
+
+       return err;
+}
+
+/**
+ * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
+ * @drive: the drive to which the taskfile command should be sent
+ * @gtf_length: total number of bytes of _GTF taskfiles
+ * @gtf_address: location of _GTF taskfile arrays
+ *
+ * Write {gtf_address, length gtf_length} in groups of
+ * REGS_PER_GTF bytes.
+ */
+static int do_drive_set_taskfiles(ide_drive_t *drive,
+                                 unsigned int gtf_length,
+                                 unsigned long gtf_address)
+{
+       int                     rc = -ENODEV, err;
+       int                     gtf_count = gtf_length / REGS_PER_GTF;
+       int                     ix;
+       struct taskfile_array   *gtf;
+
+       if (ide_noacpi)
+               return 0;
+
+       DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
+
+       if (!drive->present)
+               goto out;
+       if (!gtf_count)         /* shouldn't be here */
+               goto out;
+
+       DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
+                gtf_length, gtf_length, gtf_count, gtf_address);
+
+       if (gtf_length % REGS_PER_GTF) {
+               printk(KERN_ERR "%s: unexpected GTF length (%d)\n",
+                      __FUNCTION__, gtf_length);
+               goto out;
+       }
+
+       rc = 0;
+       for (ix = 0; ix < gtf_count; ix++) {
+               gtf = (struct taskfile_array *)
+                       (gtf_address + ix * REGS_PER_GTF);
+
+               /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
+               err = taskfile_load_raw(drive, gtf);
+               if (err)
+                       rc = err;
+       }
+
+out:
+       return rc;
+}
+
+/**
+ * ide_acpi_exec_tfs - get then write drive taskfile settings
+ * @drive: the drive for which the taskfile settings should be
+ *         written.
+ *
+ * According to the ACPI spec this should be called after _STM
+ * has been evaluated for the interface. Some ACPI vendors interpret
+ * that as a hard requirement and modify the taskfile according
+ * to the Identify Drive information passed down with _STM.
+ * So one should really make sure to call this only after _STM has
+ * been executed.
+ */
+int ide_acpi_exec_tfs(ide_drive_t *drive)
+{
+       int             ret;
+       unsigned int    gtf_length;
+       unsigned long   gtf_address;
+       unsigned long   obj_loc;
+
+       if (ide_noacpi)
+               return 0;
+
+       DEBPRINT("call get_GTF, drive=%s port=%d\n", drive->name, drive->dn);
+
+       ret = do_drive_get_GTF(drive, &gtf_length, &gtf_address, &obj_loc);
+       if (ret < 0) {
+               DEBPRINT("get_GTF error (%d)\n", ret);
+               return ret;
+       }
+
+       DEBPRINT("call set_taskfiles, drive=%s\n", drive->name);
+
+       ret = do_drive_set_taskfiles(drive, gtf_length, gtf_address);
+       kfree((void *)obj_loc);
+       if (ret < 0) {
+               DEBPRINT("set_taskfiles error (%d)\n", ret);
+       }
+
+       DEBPRINT("ret=%d\n", ret);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(ide_acpi_exec_tfs);
+
+/**
+ * ide_acpi_get_timing - get the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _GTM ACPI method for the target channel.
+ *
+ */
+void ide_acpi_get_timing(ide_hwif_t *hwif)
+{
+       acpi_status             status;
+       struct acpi_buffer      output;
+       union acpi_object       *out_obj;
+
+       if (ide_noacpi)
+               return;
+
+       DEBPRINT("ENTER:\n");
+
+       if (!hwif->acpidata) {
+               DEBPRINT("no ACPI data for %s\n", hwif->name);
+               return;
+       }
+
+       /* Setting up output buffer for _GTM */
+       output.length = ACPI_ALLOCATE_BUFFER;
+       output.pointer = NULL;  /* ACPI-CA sets this; save/free it later */
+
+       /* _GTM has no input parameters */
+       status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_GTM",
+                                     NULL, &output);
+
+       DEBPRINT("_GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n",
+                status, output.pointer,
+                (unsigned long long)output.length);
+
+       if (ACPI_FAILURE(status)) {
+               DEBPRINT("Run _GTM error: status = 0x%x\n", status);
+               return;
+       }
+
+       if (!output.length || !output.pointer) {
+               DEBPRINT("Run _GTM: length or ptr is NULL (0x%llx, 0x%p)\n",
+                      (unsigned long long)output.length,
+                      output.pointer);
+               kfree(output.pointer);
+               return;
+       }
+
+       out_obj = output.pointer;
+       if (out_obj->type != ACPI_TYPE_BUFFER) {
+               kfree(output.pointer);
+               DEBPRINT("Run _GTM: error: "
+                      "expected object type of ACPI_TYPE_BUFFER, "
+                      "got 0x%x\n", out_obj->type);
+               return;
+       }
+
+       if (!out_obj->buffer.length || !out_obj->buffer.pointer ||
+           out_obj->buffer.length != sizeof(struct GTM_buffer)) {
+               kfree(output.pointer);
+               printk(KERN_ERR
+                       "%s: unexpected _GTM length (0x%x)[should be 0x%zx] or "
+                       "addr (0x%p)\n",
+                       __FUNCTION__, out_obj->buffer.length,
+                       sizeof(struct GTM_buffer), out_obj->buffer.pointer);
+               return;
+       }
+
+       memcpy(&hwif->acpidata->gtm, out_obj->buffer.pointer,
+              sizeof(struct GTM_buffer));
+
+       DEBPRINT("_GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n",
+                out_obj->buffer.pointer, out_obj->buffer.length,
+                sizeof(struct GTM_buffer));
+
+       DEBPRINT("_GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n",
+                hwif->acpidata->gtm.PIO_speed0,
+                hwif->acpidata->gtm.DMA_speed0,
+                hwif->acpidata->gtm.PIO_speed1,
+                hwif->acpidata->gtm.DMA_speed1,
+                hwif->acpidata->gtm.GTM_flags);
+
+       kfree(output.pointer);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_get_timing);
+
+/**
+ * ide_acpi_push_timing - set the channel (controller) timings
+ * @hwif: target IDE interface (channel)
+ *
+ * This function executes the _STM ACPI method for the target channel.
+ *
+ * _STM requires Identify Drive data, which has to passed as an argument.
+ * Unfortunately hd_driveid is a mangled version which we can't readily
+ * use; hence we'll get the information afresh.
+ */
+void ide_acpi_push_timing(ide_hwif_t *hwif)
+{
+       acpi_status             status;
+       struct acpi_object_list input;
+       union acpi_object       in_params[3];
+       struct ide_acpi_drive_link      *master = &hwif->acpidata->master;
+       struct ide_acpi_drive_link      *slave = &hwif->acpidata->slave;
+
+       if (ide_noacpi)
+               return;
+
+       DEBPRINT("ENTER:\n");
+
+       if (!hwif->acpidata) {
+               DEBPRINT("no ACPI data for %s\n", hwif->name);
+               return;
+       }
+
+       /* Give the GTM buffer + drive Identify data to the channel via the
+        * _STM method: */
+       /* setup input parameters buffer for _STM */
+       input.count = 3;
+       input.pointer = in_params;
+       in_params[0].type = ACPI_TYPE_BUFFER;
+       in_params[0].buffer.length = sizeof(struct GTM_buffer);
+       in_params[0].buffer.pointer = (u8 *)&hwif->acpidata->gtm;
+       in_params[1].type = ACPI_TYPE_BUFFER;
+       in_params[1].buffer.length = sizeof(struct hd_driveid);
+       in_params[1].buffer.pointer = (u8 *)&master->idbuff;
+       in_params[2].type = ACPI_TYPE_BUFFER;
+       in_params[2].buffer.length = sizeof(struct hd_driveid);
+       in_params[2].buffer.pointer = (u8 *)&slave->idbuff;
+       /* Output buffer: _STM has no output */
+
+       status = acpi_evaluate_object(hwif->acpidata->obj_handle, "_STM",
+                                     &input, NULL);
+
+       if (ACPI_FAILURE(status)) {
+               DEBPRINT("Run _STM error: status = 0x%x\n", status);
+       }
+       DEBPRINT("_STM status: %d\n", status);
+}
+EXPORT_SYMBOL_GPL(ide_acpi_push_timing);
+
+/**
+ * ide_acpi_init - initialize the ACPI link for an IDE interface
+ * @hwif: target IDE interface (channel)
+ *
+ * The ACPI spec is not quite clear when the drive identify buffer
+ * should be obtained. Calling IDENTIFY DEVICE during shutdown
+ * is not the best of ideas as the drive might already being put to
+ * sleep. And obviously we can't call it during resume.
+ * So we get the information during startup; but this means that
+ * any changes during run-time will be lost after resume.
+ */
+void ide_acpi_init(ide_hwif_t *hwif)
+{
+       int unit;
+       int                     err;
+       struct ide_acpi_drive_link      *master;
+       struct ide_acpi_drive_link      *slave;
+
+       hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
+       if (!hwif->acpidata)
+               return;
+
+       hwif->acpidata->obj_handle = ide_acpi_hwif_get_handle(hwif);
+       if (!hwif->acpidata->obj_handle) {
+               DEBPRINT("no ACPI object for %s found\n", hwif->name);
+               kfree(hwif->acpidata);
+               hwif->acpidata = NULL;
+               return;
+       }
+
+       /*
+        * The ACPI spec mandates that we send information
+        * for both drives, regardless whether they are connected
+        * or not.
+        */
+       hwif->acpidata->master.drive = &hwif->drives[0];
+       hwif->drives[0].acpidata = &hwif->acpidata->master;
+       master = &hwif->acpidata->master;
+
+       hwif->acpidata->slave.drive = &hwif->drives[1];
+       hwif->drives[1].acpidata = &hwif->acpidata->slave;
+       slave = &hwif->acpidata->slave;
+
+
+       /*
+        * Send IDENTIFY for each drive
+        */
+       if (master->drive->present) {
+               err = taskfile_lib_get_identify(master->drive, master->idbuff);
+               if (err) {
+                       DEBPRINT("identify device %s failed (%d)\n",
+                                master->drive->name, err);
+               }
+       }
+
+       if (slave->drive->present) {
+               err = taskfile_lib_get_identify(slave->drive, slave->idbuff);
+               if (err) {
+                       DEBPRINT("identify device %s failed (%d)\n",
+                                slave->drive->name, err);
+               }
+       }
+
+       if (ide_noacpionboot) {
+               DEBPRINT("ACPI methods disabled on boot\n");
+               return;
+       }
+
+       /*
+        * ACPI requires us to call _STM on startup
+        */
+       ide_acpi_get_timing(hwif);
+       ide_acpi_push_timing(hwif);
+
+       for (unit = 0; unit < MAX_DRIVES; ++unit) {
+               ide_drive_t *drive = &hwif->drives[unit];
+
+               if (drive->present) {
+                       /* Execute ACPI startup code */
+                       ide_acpi_exec_tfs(drive);
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(ide_acpi_init);
index 5a5c565..176bbc8 100644 (file)
@@ -1384,6 +1384,9 @@ static int hwif_init(ide_hwif_t *hwif)
 
 done:
        init_gendisk(hwif);
+
+       ide_acpi_init(hwif);
+
        hwif->present = 1;      /* success */
        return 1;
 
index 6c9bd51..c750f6c 100644 (file)
@@ -187,6 +187,12 @@ int noautodma = 1;
 
 EXPORT_SYMBOL(noautodma);
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+int ide_noacpi = 0;
+int ide_noacpitfs = 1;
+int ide_noacpionboot = 1;
+#endif
+
 /*
  * This is declared extern in ide.h, for access by other IDE modules:
  */
@@ -1214,10 +1220,15 @@ EXPORT_SYMBOL(system_bus_clock);
 static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 {
        ide_drive_t *drive = dev->driver_data;
+       ide_hwif_t *hwif = HWIF(drive);
        struct request rq;
        struct request_pm_state rqpm;
        ide_task_t args;
 
+       /* Call ACPI _GTM only once */
+       if (!(drive->dn % 2))
+               ide_acpi_get_timing(hwif);
+
        memset(&rq, 0, sizeof(rq));
        memset(&rqpm, 0, sizeof(rqpm));
        memset(&args, 0, sizeof(args));
@@ -1235,10 +1246,17 @@ static int generic_ide_suspend(struct device *dev, pm_message_t mesg)
 static int generic_ide_resume(struct device *dev)
 {
        ide_drive_t *drive = dev->driver_data;
+       ide_hwif_t *hwif = HWIF(drive);
        struct request rq;
        struct request_pm_state rqpm;
        ide_task_t args;
 
+       /* Call ACPI _STM only once */
+       if (!(drive->dn % 2))
+               ide_acpi_push_timing(hwif);
+
+       ide_acpi_exec_tfs(drive);
+
        memset(&rq, 0, sizeof(rq));
        memset(&rqpm, 0, sizeof(rqpm));
        memset(&args, 0, sizeof(args));
@@ -1543,6 +1561,24 @@ static int __init ide_setup(char *s)
        }
 #endif /* CONFIG_BLK_DEV_IDEPCI */
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+       if (!strcmp(s, "ide=noacpi")) {
+               //printk(" : Disable IDE ACPI support.\n");
+               ide_noacpi = 1;
+               return 1;
+       }
+       if (!strcmp(s, "ide=acpigtf")) {
+               //printk(" : Enable IDE ACPI _GTF support.\n");
+               ide_noacpitfs = 0;
+               return 1;
+       }
+       if (!strcmp(s, "ide=acpionboot")) {
+               //printk(" : Call IDE ACPI methods on boot.\n");
+               ide_noacpionboot = 0;
+               return 1;
+       }
+#endif /* CONFIG_BLK_DEV_IDEACPI */
+
        /*
         * Look for drive options:  "hdx="
         */
index fef0896..6591ff4 100644 (file)
@@ -9,9 +9,10 @@ obj-$(CONFIG_BLK_DEV_CS5530)           += cs5530.o
 obj-$(CONFIG_BLK_DEV_CS5535)           += cs5535.o
 obj-$(CONFIG_BLK_DEV_SC1200)           += sc1200.o
 obj-$(CONFIG_BLK_DEV_CY82C693)         += cy82c693.o
+obj-$(CONFIG_BLK_DEV_DELKIN)           += delkin_cb.o
 obj-$(CONFIG_BLK_DEV_HPT34X)           += hpt34x.o
 obj-$(CONFIG_BLK_DEV_HPT366)           += hpt366.o
-#obj-$(CONFIG_BLK_DEV_HPT37X)          += hpt37x.o
+obj-$(CONFIG_BLK_DEV_IT8213)           += it8213.o
 obj-$(CONFIG_BLK_DEV_IT821X)           += it821x.o
 obj-$(CONFIG_BLK_DEV_JMICRON)          += jmicron.o
 obj-$(CONFIG_BLK_DEV_NS87415)          += ns87415.o
@@ -26,6 +27,7 @@ obj-$(CONFIG_BLK_DEV_SIIMAGE)         += siimage.o
 obj-$(CONFIG_BLK_DEV_SIS5513)          += sis5513.o
 obj-$(CONFIG_BLK_DEV_SL82C105)         += sl82c105.o
 obj-$(CONFIG_BLK_DEV_SLC90E66)         += slc90e66.o
+obj-$(CONFIG_BLK_DEV_TC86C001)         += tc86c001.o
 obj-$(CONFIG_BLK_DEV_TRIFLEX)          += triflex.o
 obj-$(CONFIG_BLK_DEV_TRM290)           += trm290.o
 obj-$(CONFIG_BLK_DEV_VIA82CXXX)                += via82cxxx.o
diff --git a/drivers/ide/pci/delkin_cb.c b/drivers/ide/pci/delkin_cb.c
new file mode 100644 (file)
index 0000000..e2672fc
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ *  linux/drivers/ide/pci/delkin_cb.c
+ *
+ *  Created 20 Oct 2004 by Mark Lord
+ *
+ *  Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter
+ *
+ *  Modeled after the 16-bit PCMCIA driver: ide-cs.c
+ *
+ *  This is slightly peculiar, in that it is a PCI driver,
+ *  but is NOT an IDE PCI driver -- the IDE layer does not directly
+ *  support hot insertion/removal of PCI interfaces, so this driver
+ *  is unable to use the IDE PCI interfaces.  Instead, it uses the
+ *  same interfaces as the ide-cs (PCMCIA) driver uses.
+ *  On the plus side, the driver is also smaller/simpler this way.
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file COPYING in the main directory of this archive for
+ *  more details.
+ */
+#include <linux/autoconf.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+/*
+ * No chip documentation has yet been found,
+ * so these configuration values were pulled from
+ * a running Win98 system using "debug".
+ * This gives around 3MByte/second read performance,
+ * which is about 2/3 of what the chip is capable of.
+ *
+ * There is also a 4KByte mmio region on the card,
+ * but its purpose has yet to be reverse-engineered.
+ */
+static const u8 setup[] = {
+       0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00,
+       0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13,
+};
+
+static int __devinit
+delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id)
+{
+       unsigned long base;
+       hw_regs_t hw;
+       ide_hwif_t *hwif = NULL;
+       ide_drive_t *drive;
+       int i, rc;
+
+       rc = pci_enable_device(dev);
+       if (rc) {
+               printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc);
+               return rc;
+       }
+       rc = pci_request_regions(dev, "delkin_cb");
+       if (rc) {
+               printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc);
+               pci_disable_device(dev);
+               return rc;
+       }
+       base = pci_resource_start(dev, 0);
+       outb(0x02, base + 0x1e);        /* set nIEN to block interrupts */
+       inb(base + 0x17);               /* read status to clear interrupts */
+       for (i = 0; i < sizeof(setup); ++i) {
+               if (setup[i])
+                       outb(setup[i], base + i);
+       }
+       pci_release_regions(dev);       /* IDE layer handles regions itself */
+
+       memset(&hw, 0, sizeof(hw));
+       ide_std_init_ports(&hw, base + 0x10, base + 0x1e);
+       hw.irq = dev->irq;
+       hw.chipset = ide_pci;           /* this enables IRQ sharing */
+
+       rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave);
+       if (rc < 0) {
+               printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc);
+               pci_disable_device(dev);
+               return -ENODEV;
+       }
+       pci_set_drvdata(dev, hwif);
+       hwif->pci_dev = dev;
+       drive = &hwif->drives[0];
+       if (drive->present) {
+               drive->io_32bit = 1;
+               drive->unmask   = 1;
+       }
+       return 0;
+}
+
+static void
+delkin_cb_remove (struct pci_dev *dev)
+{
+       ide_hwif_t *hwif = pci_get_drvdata(dev);
+
+       if (hwif)
+               ide_unregister(hwif->index);
+       pci_disable_device(dev);
+}
+
+static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = {
+       { 0x1145, 0xf021, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { 0, },
+};
+MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl);
+
+static struct pci_driver driver = {
+       .name           = "Delkin-ASKA-Workbit Cardbus IDE",
+       .id_table       = delkin_cb_pci_tbl,
+       .probe          = delkin_cb_probe,
+       .remove         = delkin_cb_remove,
+};
+
+static int
+delkin_cb_init (void)
+{
+       return pci_module_init(&driver);
+}
+
+static void
+delkin_cb_exit (void)
+{
+       pci_unregister_driver(&driver);
+}
+
+module_init(delkin_cb_init);
+module_exit(delkin_cb_exit);
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE");
+MODULE_LICENSE("GPL");
+
index b486442..05be8fa 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/drivers/ide/pci/hpt366.c              Version 0.36    April 25, 2003
+ * linux/drivers/ide/pci/hpt366.c              Version 1.01    Dec 23, 2006
  *
  * Copyright (C) 1999-2003             Andre Hedrick <andre@linux-ide.org>
  * Portions Copyright (C) 2001         Sun Microsystems, Inc.
  *   channel caused the cached register value to get out of sync with the
  *   actual one, the channels weren't serialized, the turnaround shouldn't
  *   be done on 66 MHz PCI bus
- * - avoid calibrating PLL twice as the second time results in a wrong PCI
- *   frequency and thus in the wrong timings for the secondary channel
- * - disable UltraATA/133 for HPT372 by default (50 MHz DPLL clock do not
- *   allow for this speed anyway)
- * - add support for HPT302N and HPT371N clocking (the same as for HPT372N)
- * - HPT371/N are single channel chips, so avoid touching the primary channel
- *   which exists only virtually (there's no pins for it)
+ * - disable UltraATA/100 for HPT370 by default as the 33 MHz clock being used
+ *   does not allow for this speed anyway
+ * - avoid touching disabled channels (e.g. HPT371/N are single channel chips,
+ *   their primary channel is kind of virtual, it isn't tied to any pins)
  * - fix/remove bad/unused timing tables and use one set of tables for the whole
  *   HPT37x chip family; save space by introducing the separate transfer mode
  *   table in which the mode lookup is done
  *   and for HPT36x the obsolete HDIO_TRISTATE_HWIF handler was called instead
  * - pass to init_chipset() handlers a copy of the IDE PCI device structure as
  *   they tamper with its fields
- *             <source@mvista.com>
- *
+ * - pass  to the init_setup handlers a copy of the ide_pci_device_t structure
+ *   since they may tamper with its fields
+ * - prefix the driver startup messages with the real chip name
+ * - claim the extra 240 bytes of I/O space for all chips
+ * - optimize the rate masking/filtering and the drive list lookup code
+ * - use pci_get_slot() to get to the function 1 of HPT36x/374
+ * - cache offset of the channel's misc. control registers (MCRs) being used
+ *   throughout the driver
+ * - only touch the relevant MCR when detecting the cable type on HPT374's
+ *   function 1
+ * - rename all the register related variables consistently
+ * - move all the interrupt twiddling code from the speedproc handlers into
+ *   init_hwif_hpt366(), also grouping all the DMA related code together there
+ * - merge two HPT37x speedproc handlers, fix the PIO timing register mask and
+ *   separate the UltraDMA and MWDMA masks there to avoid changing PIO timings
+ *   when setting an UltraDMA mode
+ * - fix hpt3xx_tune_drive() to set the PIO mode requested, not always select
+ *   the best possible one
+ * - clean up DMA timeout handling for HPT370
+ * - switch to using the enumeration type to differ between the numerous chip
+ *   variants, matching PCI device/revision ID with the chip type early, at the
+ *   init_setup stage
+ * - extend the hpt_info structure to hold the DPLL and PCI clock frequencies,
+ *   stop duplicating it for each channel by storing the pointer in the pci_dev
+ *   structure: first, at the init_setup stage, point it to a static "template"
+ *   with only the chip type and its specific base DPLL frequency, the highest
+ *   supported DMA mode, and the chip settings table pointer filled, then, at
+ *   the init_chipset stage, allocate per-chip instance  and fill it with the
+ *   rest of the necessary information
+ * - get rid of the constant thresholds in the HPT37x PCI clock detection code,
+ *   switch  to calculating  PCI clock frequency based on the chip's base DPLL
+ *   frequency
+ * - switch to using the  DPLL clock and enable UltraATA/133 mode by default on
+ *   anything  newer than HPT370/A
+ * - fold PCI clock detection and DPLL setup code into init_chipset_hpt366(),
+ *   also fixing the interchanged 25/40 MHz PCI clock cases for HPT36x chips;
+ *   unify HPT36x/37x timing setup code and the speedproc handlers by joining
+ *   the register setting lists into the table indexed by the clock selected
+ *     Sergei Shtylyov, <sshtylyov@ru.mvista.com> or <source@mvista.com>
  */
 
-
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -332,93 +365,159 @@ static u32 sixty_six_base_hpt37x[] = {
 };
 
 #define HPT366_DEBUG_DRIVE_INFO                0
-#define HPT374_ALLOW_ATA133_6          0
-#define HPT371_ALLOW_ATA133_6          0
-#define HPT302_ALLOW_ATA133_6          0
-#define HPT372_ALLOW_ATA133_6          0
-#define HPT370_ALLOW_ATA100_5          1
+#define HPT374_ALLOW_ATA133_6          1
+#define HPT371_ALLOW_ATA133_6          1
+#define HPT302_ALLOW_ATA133_6          1
+#define HPT372_ALLOW_ATA133_6          1
+#define HPT370_ALLOW_ATA100_5          0
 #define HPT366_ALLOW_ATA66_4           1
 #define HPT366_ALLOW_ATA66_3           1
 #define HPT366_MAX_DEVS                        8
 
-#define F_LOW_PCI_33   0x23
-#define F_LOW_PCI_40   0x29
-#define F_LOW_PCI_50   0x2d
-#define F_LOW_PCI_66   0x42
+/* Supported ATA clock frequencies */
+enum ata_clock {
+       ATA_CLOCK_25MHZ,
+       ATA_CLOCK_33MHZ,
+       ATA_CLOCK_40MHZ,
+       ATA_CLOCK_50MHZ,
+       ATA_CLOCK_66MHZ,
+       NUM_ATA_CLOCKS
+};
 
 /*
- *     Hold all the highpoint quirks and revision information in one
- *     place.
+ *     Hold all the HighPoint chip information in one place.
  */
 
-struct hpt_info
-{
+struct hpt_info {
+       u8 chip_type;           /* Chip type */
        u8 max_mode;            /* Speeds allowed */
-       int revision;           /* Chipset revision */
-       int flags;              /* Chipset properties */
-#define PLL_MODE       1
-#define IS_3xxN        2
-#define PCI_66MHZ      4
-                               /* Speed table */
-       u32 *speed;
+       u8 dpll_clk;            /* DPLL clock in MHz */
+       u8 pci_clk;             /* PCI  clock in MHz */
+       u32 **settings;         /* Chipset settings table */
 };
 
-/*
- *     This wants fixing so that we do everything not by classrev
- *     (which breaks on the newest chips) but by creating an
- *     enumeration of chip variants and using that
- */
+/* Supported HighPoint chips */
+enum {
+       HPT36x,
+       HPT370,
+       HPT370A,
+       HPT374,
+       HPT372,
+       HPT372A,
+       HPT302,
+       HPT371,
+       HPT372N,
+       HPT302N,
+       HPT371N
+};
+
+static u32 *hpt36x_settings[NUM_ATA_CLOCKS] = {
+       twenty_five_base_hpt36x,
+       thirty_three_base_hpt36x,
+       forty_base_hpt36x,
+       NULL,
+       NULL
+};
+
+static u32 *hpt37x_settings[NUM_ATA_CLOCKS] = {
+       NULL,
+       thirty_three_base_hpt37x,
+       NULL,
+       fifty_base_hpt37x,
+       sixty_six_base_hpt37x
+};
+
+static struct hpt_info hpt36x __devinitdata = {
+       .chip_type      = HPT36x,
+       .max_mode       = (HPT366_ALLOW_ATA66_4 || HPT366_ALLOW_ATA66_3) ? 2 : 1,
+       .dpll_clk       = 0,    /* no DPLL */
+       .settings       = hpt36x_settings
+};
+
+static struct hpt_info hpt370 __devinitdata = {
+       .chip_type      = HPT370,
+       .max_mode       = HPT370_ALLOW_ATA100_5 ? 3 : 2,
+       .dpll_clk       = 48,
+       .settings       = hpt37x_settings
+};
+
+static struct hpt_info hpt370a __devinitdata = {
+       .chip_type      = HPT370A,
+       .max_mode       = HPT370_ALLOW_ATA100_5 ? 3 : 2,
+       .dpll_clk       = 48,
+       .settings       = hpt37x_settings
+};
+
+static struct hpt_info hpt374 __devinitdata = {
+       .chip_type      = HPT374,
+       .max_mode       = HPT374_ALLOW_ATA133_6 ? 4 : 3,
+       .dpll_clk       = 48,
+       .settings       = hpt37x_settings
+};
+
+static struct hpt_info hpt372 __devinitdata = {
+       .chip_type      = HPT372,
+       .max_mode       = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+       .dpll_clk       = 55,
+       .settings       = hpt37x_settings
+};
+
+static struct hpt_info hpt372a __devinitdata = {
+       .chip_type      = HPT372A,
+       .max_mode       = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+       .dpll_clk       = 66,
+       .settings       = hpt37x_settings
+};
+
+static struct hpt_info hpt302 __devinitdata = {
+       .chip_type      = HPT302,
+       .max_mode       = HPT302_ALLOW_ATA133_6 ? 4 : 3,
+       .dpll_clk       = 66,
+       .settings       = hpt37x_settings
+};
+
+static struct hpt_info hpt371 __devinitdata = {
+       .chip_type      = HPT371,
+       .max_mode       = HPT371_ALLOW_ATA133_6 ? 4 : 3,
+       .dpll_clk       = 66,
+       .settings       = hpt37x_settings
+};
+
+static struct hpt_info hpt372n __devinitdata = {
+       .chip_type      = HPT372N,
+       .max_mode       = HPT372_ALLOW_ATA133_6 ? 4 : 3,
+       .dpll_clk       = 77,
+       .settings       = hpt37x_settings
+};
+
+static struct hpt_info hpt302n __devinitdata = {
+       .chip_type      = HPT302N,
+       .max_mode       = HPT302_ALLOW_ATA133_6 ? 4 : 3,
+       .dpll_clk       = 77,
+};
 
-static __devinit u32 hpt_revision (struct pci_dev *dev)
+static struct hpt_info hpt371n __devinitdata = {
+       .chip_type      = HPT371N,
+       .max_mode       = HPT371_ALLOW_ATA133_6 ? 4 : 3,
+       .dpll_clk       = 77,
+       .settings       = hpt37x_settings
+};
+
+static int check_in_drive_list(ide_drive_t *drive, const char **list)
 {
-       u32 class_rev;
-       pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-       class_rev &= 0xff;
-
-       switch(dev->device) {
-               /* Remap new 372N onto 372 */
-               case PCI_DEVICE_ID_TTI_HPT372N:
-                       class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
-               case PCI_DEVICE_ID_TTI_HPT374:
-                       class_rev = PCI_DEVICE_ID_TTI_HPT374; break;
-               case PCI_DEVICE_ID_TTI_HPT371:
-                       class_rev = PCI_DEVICE_ID_TTI_HPT371; break;
-               case PCI_DEVICE_ID_TTI_HPT302:
-                       class_rev = PCI_DEVICE_ID_TTI_HPT302; break;
-               case PCI_DEVICE_ID_TTI_HPT372:
-                       class_rev = PCI_DEVICE_ID_TTI_HPT372; break;
-               default:
-                       break;
-       }
-       return class_rev;
-}
+       struct hd_driveid *id = drive->id;
 
-static int check_in_drive_lists(ide_drive_t *drive, const char **list);
+       while (*list)
+               if (!strcmp(*list++,id->model))
+                       return 1;
+       return 0;
+}
 
-static u8 hpt3xx_ratemask (ide_drive_t *drive)
+static u8 hpt3xx_ratemask(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif        = drive->hwif;
-       struct hpt_info *info   = ide_get_hwifdata(hwif);
-       u8 mode                 = 0;
-
-       /* FIXME: TODO - move this to set info->mode once at boot */
-
-       if (info->revision >= 8) {              /* HPT374 */
-               mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
-       } else if (info->revision >= 7) {       /* HPT371 */
-               mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
-       } else if (info->revision >= 6) {       /* HPT302 */
-               mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
-       } else if (info->revision >= 5) {       /* HPT372 */
-               mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
-       } else if (info->revision >= 4) {       /* HPT370A */
-               mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
-       } else if (info->revision >= 3) {       /* HPT370 */
-               mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
-               mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
-       } else {                                /* HPT366 and HPT368 */
-               mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
-       }
+       struct hpt_info *info   = pci_get_drvdata(HWIF(drive)->pci_dev);
+       u8 mode                 = info->max_mode;
+
        if (!eighty_ninty_three(drive) && mode)
                mode = min(mode, (u8)1);
        return mode;
@@ -429,75 +528,61 @@ static u8 hpt3xx_ratemask (ide_drive_t *drive)
  *     either PIO or UDMA modes 0,4,5
  */
  
-static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
+static u8 hpt3xx_ratefilter(ide_drive_t *drive, u8 speed)
 {
-       ide_hwif_t *hwif        = drive->hwif;
-       struct hpt_info *info   = ide_get_hwifdata(hwif);
+       struct hpt_info *info   = pci_get_drvdata(HWIF(drive)->pci_dev);
+       u8 chip_type            = info->chip_type;
        u8 mode                 = hpt3xx_ratemask(drive);
 
        if (drive->media != ide_disk)
                return min(speed, (u8)XFER_PIO_4);
 
-       switch(mode) {
+       switch (mode) {
                case 0x04:
-                       speed = min(speed, (u8)XFER_UDMA_6);
+                       speed = min_t(u8, speed, XFER_UDMA_6);
                        break;
                case 0x03:
-                       speed = min(speed, (u8)XFER_UDMA_5);
-                       if (info->revision >= 5)
+                       speed = min_t(u8, speed, XFER_UDMA_5);
+                       if (chip_type >= HPT374)
                                break;
-                       if (check_in_drive_lists(drive, bad_ata100_5))
-                               speed = min(speed, (u8)XFER_UDMA_4);
-                       break;
+                       if (!check_in_drive_list(drive, bad_ata100_5))
+                               goto check_bad_ata33;
+                       /* fall thru */
                case 0x02:
-                       speed = min(speed, (u8)XFER_UDMA_4);
-       /*
-        * CHECK ME, Does this need to be set to 5 ??
-        */
-                       if (info->revision >= 3)
-                               break;
-                       if ((check_in_drive_lists(drive, bad_ata66_4)) ||
-                           (!(HPT366_ALLOW_ATA66_4)))
-                               speed = min(speed, (u8)XFER_UDMA_3);
-                       if ((check_in_drive_lists(drive, bad_ata66_3)) ||
-                           (!(HPT366_ALLOW_ATA66_3)))
-                               speed = min(speed, (u8)XFER_UDMA_2);
-                       break;
+                       speed = min_t(u8, speed, XFER_UDMA_4);
+
+                       /*
+                        * CHECK ME, Does this need to be changed to HPT374 ??
+                        */
+                       if (chip_type >= HPT370)
+                               goto check_bad_ata33;
+                       if (HPT366_ALLOW_ATA66_4 &&
+                           !check_in_drive_list(drive, bad_ata66_4))
+                               goto check_bad_ata33;
+
+                       speed = min_t(u8, speed, XFER_UDMA_3);
+                       if (HPT366_ALLOW_ATA66_3 &&
+                           !check_in_drive_list(drive, bad_ata66_3))
+                               goto check_bad_ata33;
+                       /* fall thru */
                case 0x01:
-                       speed = min(speed, (u8)XFER_UDMA_2);
-       /*
-        * CHECK ME, Does this need to be set to 5 ??
-        */
-                       if (info->revision >= 3)
+                       speed = min_t(u8, speed, XFER_UDMA_2);
+
+               check_bad_ata33:
+                       if (chip_type >= HPT370A)
                                break;
-                       if (check_in_drive_lists(drive, bad_ata33))
-                               speed = min(speed, (u8)XFER_MW_DMA_2);
-                       break;
+                       if (!check_in_drive_list(drive, bad_ata33))
+                               break;
+                       /* fall thru */
                case 0x00:
                default:
-                       speed = min(speed, (u8)XFER_MW_DMA_2);
+                       speed = min_t(u8, speed, XFER_MW_DMA_2);
                        break;
        }
        return speed;
 }
 
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-       struct hd_driveid *id = drive->id;
-
-       if (quirk_drives == list) {
-               while (*list)
-                       if (strstr(id->model, *list++))
-                               return 1;
-       } else {
-               while (*list)
-                       if (!strcmp(*list++,id->model))
-                               return 1;
-       }
-       return 0;
-}
-
-static u32 pci_bus_clock_list(u8 speed, u32 *chipset_table)
+static u32 get_speed_setting(u8 speed, struct hpt_info *info)
 {
        int i;
 
@@ -510,228 +595,161 @@ static u32 pci_bus_clock_list(u8 speed, u32 *chipset_table)
        for (i = 0; i < ARRAY_SIZE(xfer_speeds) - 1; i++)
                if (xfer_speeds[i] == speed)
                        break;
-       return chipset_table[i];
+       /*
+        * NOTE: info->settings only points to the pointer
+        * to the list of the actual register values
+        */
+       return (*info->settings)[i];
 }
 
 static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 {
-       ide_hwif_t *hwif        = drive->hwif;
-       struct pci_dev *dev     = hwif->pci_dev;
-       struct hpt_info *info   = ide_get_hwifdata(hwif);
-       u8 speed                = hpt3xx_ratefilter(drive, xferspeed);
-       u8 regtime              = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
-       u8 regfast              = (hwif->channel) ? 0x55 : 0x51;
-       u8 drive_fast           = 0;
-       u32 reg1 = 0, reg2      = 0;
-
-       /*
-        * Disable the "fast interrupt" prediction.
-        */
-       pci_read_config_byte(dev, regfast, &drive_fast);
-       if (drive_fast & 0x80)
-               pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
-
-       reg2 = pci_bus_clock_list(speed, info->speed);
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev  *dev    = hwif->pci_dev;
+       struct hpt_info *info   = pci_get_drvdata(dev);
+       u8  speed               = hpt3xx_ratefilter(drive, xferspeed);
+       u8  itr_addr            = drive->dn ? 0x44 : 0x40;
+       u32 itr_mask            = speed < XFER_MW_DMA_0 ? 0x30070000 :
+                                (speed < XFER_UDMA_0   ? 0xc0070000 : 0xc03800ff);
+       u32 new_itr             = get_speed_setting(speed, info);
+       u32 old_itr             = 0;
 
        /*
-        * Disable on-chip PIO FIFO/buffer
-        *  (to avoid problems handling I/O errors later)
+        * Disable on-chip PIO FIFO/buffer (and PIO MST mode as well)
+        * to avoid problems handling I/O errors later
         */
-       pci_read_config_dword(dev, regtime, &reg1);
-       if (speed >= XFER_MW_DMA_0) {
-               reg2 = (reg2 & ~0xc0000000) | (reg1 & 0xc0000000);
-       } else {
-               reg2 = (reg2 & ~0x30070000) | (reg1 & 0x30070000);
-       }       
-       reg2 &= ~0x80000000;
+       pci_read_config_dword(dev, itr_addr, &old_itr);
+       new_itr  = (new_itr & ~itr_mask) | (old_itr & itr_mask);
+       new_itr &= ~0xc0000000;
 
-       pci_write_config_dword(dev, regtime, reg2);
+       pci_write_config_dword(dev, itr_addr, new_itr);
 
        return ide_config_drive_speed(drive, speed);
 }
 
-static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt37x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
 {
-       ide_hwif_t *hwif        = drive->hwif;
-       struct pci_dev *dev = hwif->pci_dev;
-       struct hpt_info *info   = ide_get_hwifdata(hwif);
-       u8 speed        = hpt3xx_ratefilter(drive, xferspeed);
-       u8 regfast      = (drive->hwif->channel) ? 0x55 : 0x51;
-       u8 drive_pci    = 0x40 + (drive->dn * 4);
-       u8 new_fast     = 0, drive_fast = 0;
-       u32 list_conf   = 0, drive_conf = 0;
-       u32 conf_mask   = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-
-       /*
-        * Disable the "fast interrupt" prediction.
-        * don't holdoff on interrupts. (== 0x01 despite what the docs say) 
-        */
-       pci_read_config_byte(dev, regfast, &drive_fast);
-       new_fast = drive_fast;
-       if (new_fast & 0x02)
-               new_fast &= ~0x02;
-
-#ifdef HPT_DELAY_INTERRUPT
-       if (new_fast & 0x01)
-               new_fast &= ~0x01;
-#else
-       if ((new_fast & 0x01) == 0)
-               new_fast |= 0x01;
-#endif
-       if (new_fast != drive_fast)
-               pci_write_config_byte(dev, regfast, new_fast);
-
-       list_conf = pci_bus_clock_list(speed, info->speed);
-
-       pci_read_config_dword(dev, drive_pci, &drive_conf);
-       list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev  *dev    = hwif->pci_dev;
+       struct hpt_info *info   = pci_get_drvdata(dev);
+       u8  speed               = hpt3xx_ratefilter(drive, xferspeed);
+       u8  itr_addr            = 0x40 + (drive->dn * 4);
+       u32 itr_mask            = speed < XFER_MW_DMA_0 ? 0x303c0000 :
+                                (speed < XFER_UDMA_0   ? 0xc03c0000 : 0xc1c001ff);
+       u32 new_itr             = get_speed_setting(speed, info);
+       u32 old_itr             = 0;
+
+       pci_read_config_dword(dev, itr_addr, &old_itr);
+       new_itr = (new_itr & ~itr_mask) | (old_itr & itr_mask);
        
        if (speed < XFER_MW_DMA_0)
-               list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-       pci_write_config_dword(dev, drive_pci, list_conf);
+               new_itr &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
+       pci_write_config_dword(dev, itr_addr, new_itr);
 
        return ide_config_drive_speed(drive, speed);
 }
 
-static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
+static int hpt3xx_tune_chipset(ide_drive_t *drive, u8 speed)
 {
-       ide_hwif_t *hwif        = drive->hwif;
-       struct pci_dev *dev     = hwif->pci_dev;
-       struct hpt_info *info   = ide_get_hwifdata(hwif);
-       u8 speed        = hpt3xx_ratefilter(drive, xferspeed);
-       u8 regfast      = (drive->hwif->channel) ? 0x55 : 0x51;
-       u8 drive_fast   = 0, drive_pci = 0x40 + (drive->dn * 4);
-       u32 list_conf   = 0, drive_conf = 0;
-       u32 conf_mask   = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
-
-       /*
-        * Disable the "fast interrupt" prediction.
-        * don't holdoff on interrupts. (== 0x01 despite what the docs say)
-        */
-       pci_read_config_byte(dev, regfast, &drive_fast);
-       drive_fast &= ~0x07;
-       pci_write_config_byte(dev, regfast, drive_fast);
-
-       list_conf = pci_bus_clock_list(speed, info->speed);
-       pci_read_config_dword(dev, drive_pci, &drive_conf);
-       list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
-       if (speed < XFER_MW_DMA_0)
-               list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
-       pci_write_config_dword(dev, drive_pci, list_conf);
-
-       return ide_config_drive_speed(drive, speed);
-}
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct hpt_info *info   = pci_get_drvdata(hwif->pci_dev);
 
-static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
-{
-       ide_hwif_t *hwif        = drive->hwif;
-       struct hpt_info *info   = ide_get_hwifdata(hwif);
-
-       if (info->revision >= 8)
-               return hpt372_tune_chipset(drive, speed); /* not a typo */
-       else if (info->revision >= 5)
-               return hpt372_tune_chipset(drive, speed);
-       else if (info->revision >= 3)
-               return hpt370_tune_chipset(drive, speed);
+       if (info->chip_type >= HPT370)
+               return hpt37x_tune_chipset(drive, speed);
        else    /* hpt368: hpt_minimum_revision(dev, 2) */
                return hpt36x_tune_chipset(drive, speed);
 }
 
-static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
+static void hpt3xx_tune_drive(ide_drive_t *drive, u8 pio)
 {
-       pio = ide_get_best_pio_mode(drive, 255, pio, NULL);
-       (void) hpt3xx_tune_chipset(drive, (XFER_PIO_0 + pio));
+       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+       (void) hpt3xx_tune_chipset (drive, XFER_PIO_0 + pio);
 }
 
 /*
  * This allows the configuration of ide_pci chipset registers
  * for cards that learn about the drive's UDMA, DMA, PIO capabilities
- * after the drive is reported by the OS.  Initially for designed for
+ * after the drive is reported by the OS.  Initially designed for
  * HPT366 UDMA chipset by HighPoint|Triones Technologies, Inc.
  *
- * check_in_drive_lists(drive, bad_ata66_4)
- * check_in_drive_lists(drive, bad_ata66_3)
- * check_in_drive_lists(drive, bad_ata33)
- *
  */
-static int config_chipset_for_dma (ide_drive_t *drive)
+static int config_chipset_for_dma(ide_drive_t *drive)
 {
        u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
-       ide_hwif_t *hwif = drive->hwif;
-       struct hpt_info *info   = ide_get_hwifdata(hwif);
 
        if (!speed)
                return 0;
 
-       /* If we don't have any timings we can't do a lot */
-       if (info->speed == NULL)
-               return 0;
-
        (void) hpt3xx_tune_chipset(drive, speed);
        return ide_dma_enable(drive);
 }
 
-static int hpt3xx_quirkproc (ide_drive_t *drive)
+static int hpt3xx_quirkproc(ide_drive_t *drive)
 {
-       return ((int) check_in_drive_lists(drive, quirk_drives));
+       struct hd_driveid *id   = drive->id;
+       const  char **list      = quirk_drives;
+
+       while (*list)
+               if (strstr(id->model, *list++))
+                       return 1;
+       return 0;
 }
 
-static void hpt3xx_intrproc (ide_drive_t *drive)
+static void hpt3xx_intrproc(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif = drive->hwif;
+       ide_hwif_t *hwif = HWIF(drive);
 
        if (drive->quirk_list)
                return;
        /* drives in the quirk_list may not like intr setups/cleanups */
-       hwif->OUTB(drive->ctl|2, IDE_CONTROL_REG);
+       hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);
 }
 
-static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
+static void hpt3xx_maskproc(ide_drive_t *drive, int mask)
 {
-       ide_hwif_t *hwif = drive->hwif;
-       struct hpt_info *info = ide_get_hwifdata(hwif);
-       struct pci_dev *dev = hwif->pci_dev;
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev  *dev    = hwif->pci_dev;
+       struct hpt_info *info   = pci_get_drvdata(dev);
 
        if (drive->quirk_list) {
-               if (info->revision >= 3) {
-                       u8 reg5a = 0;
-                       pci_read_config_byte(dev, 0x5a, &reg5a);
-                       if (((reg5a & 0x10) >> 4) != mask)
-                               pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
+               if (info->chip_type >= HPT370) {
+                       u8 scr1 = 0;
+
+                       pci_read_config_byte(dev, 0x5a, &scr1);
+                       if (((scr1 & 0x10) >> 4) != mask) {
+                               if (mask)
+                                       scr1 |=  0x10;
+                               else
+                                       scr1 &= ~0x10;
+                               pci_write_config_byte(dev, 0x5a, scr1);
+                       }
                } else {
-                       if (mask) {
+                       if (mask)
                                disable_irq(hwif->irq);
-                       } else {
-                               enable_irq(hwif->irq);
-                       }
+                       else
+                               enable_irq (hwif->irq);
                }
-       } else {
-               if (IDE_CONTROL_REG)
-                       hwif->OUTB(mask ? (drive->ctl | 2) :
-                                                (drive->ctl & ~2),
-                                                IDE_CONTROL_REG);
-       }
+       } else
+               hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2),
+                          IDE_CONTROL_REG);
 }
 
-static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
+static int hpt366_config_drive_xfer_rate(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif        = drive->hwif;
+       ide_hwif_t *hwif        = HWIF(drive);
        struct hd_driveid *id   = drive->id;
 
        drive->init_speed = 0;
 
        if ((id->capability & 1) && drive->autodma) {
-
-               if (ide_use_dma(drive)) {
-                       if (config_chipset_for_dma(drive))
-                               return hwif->ide_dma_on(drive);
-               }
+               if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+                       return hwif->ide_dma_on(drive);
 
                goto fast_ata_pio;
 
        } else if ((id->capability & 8) || (id->field_valid & 2)) {
 fast_ata_pio:
-               hpt3xx_tune_drive(drive, 5);
+               hpt3xx_tune_drive(drive, 255);
                return hwif->ide_dma_off_quietly(drive);
        }
        /* IORDY not supported */
@@ -739,31 +757,48 @@ fast_ata_pio:
 }
 
 /*
- * This is specific to the HPT366 UDMA bios chipset
+ * This is specific to the HPT366 UDMA chipset
  * by HighPoint|Triones Technologies, Inc.
  */
-static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
+static int hpt366_ide_dma_lostirq(ide_drive_t *drive)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
-       u8 reg50h = 0, reg52h = 0, reg5ah = 0;
-
-       pci_read_config_byte(dev, 0x50, &reg50h);
-       pci_read_config_byte(dev, 0x52, &reg52h);
-       pci_read_config_byte(dev, 0x5a, &reg5ah);
-       printk("%s: (%s)  reg50h=0x%02x, reg52h=0x%02x, reg5ah=0x%02x\n",
-               drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
-       if (reg5ah & 0x10)
-               pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
+       struct pci_dev *dev = HWIF(drive)->pci_dev;
+       u8 mcr1 = 0, mcr3 = 0, scr1 = 0;
+
+       pci_read_config_byte(dev, 0x50, &mcr1);
+       pci_read_config_byte(dev, 0x52, &mcr3);
+       pci_read_config_byte(dev, 0x5a, &scr1);
+       printk("%s: (%s)  mcr1=0x%02x, mcr3=0x%02x, scr1=0x%02x\n",
+               drive->name, __FUNCTION__, mcr1, mcr3, scr1);
+       if (scr1 & 0x10)
+               pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
        return __ide_dma_lostirq(drive);
 }
 
-static void hpt370_clear_engine (ide_drive_t *drive)
+static void hpt370_clear_engine(ide_drive_t *drive)
 {
-       u8 regstate = HWIF(drive)->channel ? 0x54 : 0x50;
-       pci_write_config_byte(HWIF(drive)->pci_dev, regstate, 0x37);
+       ide_hwif_t *hwif = HWIF(drive);
+
+       pci_write_config_byte(hwif->pci_dev, hwif->select_data, 0x37);
        udelay(10);
 }
 
+static void hpt370_irq_timeout(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif        = HWIF(drive);
+       u16 bfifo               = 0;
+       u8  dma_cmd;
+
+       pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
+       printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo & 0x1ff);
+
+       /* get DMA command mode */
+       dma_cmd = hwif->INB(hwif->dma_command);
+       /* stop DMA */
+       hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
+       hpt370_clear_engine(drive);
+}
+
 static void hpt370_ide_dma_start(ide_drive_t *drive)
 {
 #ifdef HPT_RESET_STATE_ENGINE
@@ -772,64 +807,35 @@ static void hpt370_ide_dma_start(ide_drive_t *drive)
        ide_dma_start(drive);
 }
 
-static int hpt370_ide_dma_end (ide_drive_t *drive)
+static int hpt370_ide_dma_end(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
-       u8 dma_stat             = hwif->INB(hwif->dma_status);
+       u8  dma_stat            = hwif->INB(hwif->dma_status);
 
        if (dma_stat & 0x01) {
                /* wait a little */
                udelay(20);
                dma_stat = hwif->INB(hwif->dma_status);
+               if (dma_stat & 0x01)
+                       hpt370_irq_timeout(drive);
        }
-       if ((dma_stat & 0x01) != 0) 
-               /* fallthrough */
-               (void) HWIF(drive)->ide_dma_timeout(drive);
-
        return __ide_dma_end(drive);
 }
 
-static void hpt370_lostirq_timeout (ide_drive_t *drive)
+static int hpt370_ide_dma_timeout(ide_drive_t *drive)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
-       u8 bfifo = 0, reginfo   = hwif->channel ? 0x56 : 0x52;
-       u8 dma_stat = 0, dma_cmd = 0;
-
-       pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
-       printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo);
-       hpt370_clear_engine(drive);
-       /* get dma command mode */
-       dma_cmd = hwif->INB(hwif->dma_command);
-       /* stop dma */
-       hwif->OUTB(dma_cmd & ~0x1, hwif->dma_command);
-       dma_stat = hwif->INB(hwif->dma_status);
-       /* clear errors */
-       hwif->OUTB(dma_stat | 0x6, hwif->dma_status);
-}
-
-static int hpt370_ide_dma_timeout (ide_drive_t *drive)
-{
-       hpt370_lostirq_timeout(drive);
-       hpt370_clear_engine(drive);
+       hpt370_irq_timeout(drive);
        return __ide_dma_timeout(drive);
 }
 
-static int hpt370_ide_dma_lostirq (ide_drive_t *drive)
-{
-       hpt370_lostirq_timeout(drive);
-       hpt370_clear_engine(drive);
-       return __ide_dma_lostirq(drive);
-}
-
 /* returns 1 if DMA IRQ issued, 0 otherwise */
 static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        u16 bfifo               = 0;
-       u8 reginfo              = hwif->channel ? 0x56 : 0x52;
-       u8 dma_stat;
+       u8  dma_stat;
 
-       pci_read_config_word(hwif->pci_dev, reginfo, &bfifo);
+       pci_read_config_word(hwif->pci_dev, hwif->select_data + 2, &bfifo);
        if (bfifo & 0x1FF) {
 //             printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
                return 0;
@@ -837,7 +843,7 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
 
        dma_stat = hwif->INB(hwif->dma_status);
        /* return 1 if INTR asserted */
-       if ((dma_stat & 4) == 4)
+       if (dma_stat & 4)
                return 1;
 
        if (!drive->waiting_for_dma)
@@ -846,17 +852,17 @@ static int hpt374_ide_dma_test_irq(ide_drive_t *drive)
        return 0;
 }
 
-static int hpt374_ide_dma_end (ide_drive_t *drive)
+static int hpt374_ide_dma_end(ide_drive_t *drive)
 {
-       struct pci_dev *dev     = HWIF(drive)->pci_dev;
        ide_hwif_t *hwif        = HWIF(drive);
-       u8 msc_stat = 0, mscreg = hwif->channel ? 0x54 : 0x50;
-       u8 bwsr_stat = 0, bwsr_mask = hwif->channel ? 0x02 : 0x01;
-
-       pci_read_config_byte(dev, 0x6a, &bwsr_stat);
-       pci_read_config_byte(dev, mscreg, &msc_stat);
-       if ((bwsr_stat & bwsr_mask) == bwsr_mask)
-               pci_write_config_byte(dev, mscreg, msc_stat|0x30);
+       struct pci_dev  *dev    = hwif->pci_dev;
+       u8 mcr  = 0, mcr_addr   = hwif->select_data;
+       u8 bwsr = 0, mask       = hwif->channel ? 0x02 : 0x01;
+
+       pci_read_config_byte(dev, 0x6a, &bwsr);
+       pci_read_config_byte(dev, mcr_addr, &mcr);
+       if (bwsr & mask)
+               pci_write_config_byte(dev, mcr_addr, mcr | 0x30);
        return __ide_dma_end(drive);
 }
 
@@ -866,40 +872,37 @@ static int hpt374_ide_dma_end (ide_drive_t *drive)
  *     @mode: clocking mode (0x21 for write, 0x23 otherwise)
  *
  *     Switch the DPLL clock on the HPT3xxN devices. This is a right mess.
- *     NOTE: avoid touching the disabled primary channel on HPT371N -- it
- *     doesn't physically exist anyway...
  */
 
 static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
 {
-       u8 mcr1, scr2 = hwif->INB(hwif->dma_master + 0x7b);
+       u8 scr2 = hwif->INB(hwif->dma_master + 0x7b);
 
        if ((scr2 & 0x7f) == mode)
                return;
 
-       /* MISC. control register 1 has the channel enable bit... */
-       mcr1 = hwif->INB(hwif->dma_master + 0x70);
-
        /* Tristate the bus */
-       if (mcr1 & 0x04)
-               hwif->OUTB(0x80, hwif->dma_master + 0x73);
+       hwif->OUTB(0x80, hwif->dma_master + 0x73);
        hwif->OUTB(0x80, hwif->dma_master + 0x77);
 
        /* Switch clock and reset channels */
        hwif->OUTB(mode, hwif->dma_master + 0x7b);
        hwif->OUTB(0xc0, hwif->dma_master + 0x79);
 
-       /* Reset state machines */
-       if (mcr1 & 0x04)
-               hwif->OUTB(0x37, hwif->dma_master + 0x70);
-       hwif->OUTB(0x37, hwif->dma_master + 0x74);
+       /*
+        * Reset the state machines.
+        * NOTE: avoid accidentally enabling the disabled channels.
+        */
+       hwif->OUTB(hwif->INB(hwif->dma_master + 0x70) | 0x32,
+                  hwif->dma_master + 0x70);
+       hwif->OUTB(hwif->INB(hwif->dma_master + 0x74) | 0x32,
+                  hwif->dma_master + 0x74);
 
        /* Complete reset */
        hwif->OUTB(0x00, hwif->dma_master + 0x79);
 
        /* Reconnect channels to bus */
-       if (mcr1 & 0x04)
-               hwif->OUTB(0x00, hwif->dma_master + 0x73);
+       hwif->OUTB(0x00, hwif->dma_master + 0x73);
        hwif->OUTB(0x00, hwif->dma_master + 0x77);
 }
 
@@ -914,14 +917,12 @@ static void hpt3xxn_set_clock(ide_hwif_t *hwif, u8 mode)
 
 static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
 {
-       ide_hwif_t *hwif        = HWIF(drive);
-       u8 wantclock            = rq_data_dir(rq) ? 0x23 : 0x21;
-
-       hpt3xxn_set_clock(hwif, wantclock);
+       hpt3xxn_set_clock(HWIF(drive), rq_data_dir(rq) ? 0x23 : 0x21);
 }
 
 /* 
  * Set/get power state for a drive.
+ * NOTE: affects both drives on each channel.
  *
  * When we turn the power back on, we need to re-initialize things.
  */
@@ -929,26 +930,18 @@ static void hpt3xxn_rw_disk(ide_drive_t *drive, struct request *rq)
 
 static int hpt3xx_busproc(ide_drive_t *drive, int state)
 {
-       ide_hwif_t *hwif        = drive->hwif;
+       ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
-       u8  tristate, resetmask, bus_reg = 0;
-       u16 tri_reg = 0;
+       u8  mcr_addr            = hwif->select_data + 2;
+       u8  resetmask           = hwif->channel ? 0x80 : 0x40;
+       u8  bsr2                = 0;
+       u16 mcr                 = 0;
 
        hwif->bus_state = state;
 
-       if (hwif->channel) { 
-               /* secondary channel */
-               tristate  = 0x56;
-               resetmask = 0x80;
-       } else { 
-               /* primary channel */
-               tristate  = 0x52;
-               resetmask = 0x40;
-       }
-
        /* Grab the status. */
-       pci_read_config_word(dev, tristate, &tri_reg);
-       pci_read_config_byte(dev, 0x59, &bus_reg);
+       pci_read_config_word(dev, mcr_addr, &mcr);
+       pci_read_config_byte(dev, 0x59, &bsr2);
 
        /*
         * Set the state. We don't set it if we don't need to do so.
@@ -956,22 +949,22 @@ static int hpt3xx_busproc(ide_drive_t *drive, int state)
         */
        switch (state) {
        case BUSSTATE_ON:
-               if (!(bus_reg & resetmask))
+               if (!(bsr2 & resetmask))
                        return 0;
                hwif->drives[0].failures = hwif->drives[1].failures = 0;
 
-               pci_write_config_byte(dev, 0x59, bus_reg & ~resetmask);
-               pci_write_config_word(dev, tristate, tri_reg & ~TRISTATE_BIT);
+               pci_write_config_byte(dev, 0x59, bsr2 & ~resetmask);
+               pci_write_config_word(dev, mcr_addr, mcr & ~TRISTATE_BIT);
                return 0;
        case BUSSTATE_OFF:
-               if ((bus_reg & resetmask) && !(tri_reg & TRISTATE_BIT))
+               if ((bsr2 & resetmask) && !(mcr & TRISTATE_BIT))
                        return 0;
-               tri_reg &= ~TRISTATE_BIT;
+               mcr &= ~TRISTATE_BIT;
                break;
        case BUSSTATE_TRISTATE:
-               if ((bus_reg & resetmask) &&  (tri_reg & TRISTATE_BIT))
+               if ((bsr2 & resetmask) &&  (mcr & TRISTATE_BIT))
                        return 0;
-               tri_reg |= TRISTATE_BIT;
+               mcr |= TRISTATE_BIT;
                break;
        default:
                return -EINVAL;
@@ -980,268 +973,320 @@ static int hpt3xx_busproc(ide_drive_t *drive, int state)
        hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
        hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
 
-       pci_write_config_word(dev, tristate, tri_reg);
-       pci_write_config_byte(dev, 0x59, bus_reg | resetmask);
+       pci_write_config_word(dev, mcr_addr, mcr);
+       pci_write_config_byte(dev, 0x59, bsr2 | resetmask);
        return 0;
 }
 
-static void __devinit hpt366_clocking(ide_hwif_t *hwif)
+/**
+ *     hpt37x_calibrate_dpll   -       calibrate the DPLL
+ *     @dev: PCI device
+ *
+ *     Perform a calibration cycle on the DPLL.
+ *     Returns 1 if this succeeds
+ */
+static int __devinit hpt37x_calibrate_dpll(struct pci_dev *dev, u16 f_low, u16 f_high)
 {
-       u32 reg1        = 0;
-       struct hpt_info *info = ide_get_hwifdata(hwif);
+       u32 dpll = (f_high << 16) | f_low | 0x100;
+       u8  scr2;
+       int i;
 
-       pci_read_config_dword(hwif->pci_dev, 0x40, &reg1);
+       pci_write_config_dword(dev, 0x5c, dpll);
 
-       /* detect bus speed by looking at control reg timing: */
-       switch((reg1 >> 8) & 7) {
-               case 5:
-                       info->speed = forty_base_hpt36x;
-                       break;
-               case 9:
-                       info->speed = twenty_five_base_hpt36x;
-                       break;
-               case 7:
-               default:
-                       info->speed = thirty_three_base_hpt36x;
+       /* Wait for oscillator ready */
+       for(i = 0; i < 0x5000; ++i) {
+               udelay(50);
+               pci_read_config_byte(dev, 0x5b, &scr2);
+               if (scr2 & 0x80)
                        break;
        }
+       /* See if it stays ready (we'll just bail out if it's not yet) */
+       for(i = 0; i < 0x1000; ++i) {
+               pci_read_config_byte(dev, 0x5b, &scr2);
+               /* DPLL destabilized? */
+               if(!(scr2 & 0x80))
+                       return 0;
+       }
+       /* Turn off tuning, we have the DPLL set */
+       pci_read_config_dword (dev, 0x5c, &dpll);
+       pci_write_config_dword(dev, 0x5c, (dpll & ~0x100));
+       return 1;
 }
 
-static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
+static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
 {
-       struct hpt_info *info = ide_get_hwifdata(hwif);
-       struct pci_dev *dev = hwif->pci_dev;
-       int adjust, i;
-       u16 freq = 0;
-       u32 pll, temp = 0;
-       u8 reg5bh = 0, mcr1 = 0;
-       
+       struct hpt_info *info   = kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
+       unsigned long io_base   = pci_resource_start(dev, 4);
+       u8 pci_clk,  dpll_clk   = 0;    /* PCI and DPLL clock in MHz */
+       enum ata_clock  clock;
+
+       if (info == NULL) {
+               printk(KERN_ERR "%s: out of memory!\n", name);
+               return -ENOMEM;
+       }
+
        /*
-        * default to pci clock. make sure MA15/16 are set to output
-        * to prevent drives having problems with 40-pin cables. Needed
-        * for some drives such as IBM-DTLA which will not enter ready
-        * state on reset when PDIAG is a input.
-        *
-        * ToDo: should we set 0x21 when using PLL mode ?
+        * Copy everything from a static "template" structure
+        * to just allocated per-chip hpt_info structure.
         */
-       pci_write_config_byte(dev, 0x5b, 0x23);
+       *info = *(struct hpt_info *)pci_get_drvdata(dev);
 
        /*
-        * We'll have to read f_CNT value in order to determine
-        * the PCI clock frequency according to the following ratio:
-        *
-        * f_CNT = Fpci * 192 / Fdpll
-        *
-        * First try reading the register in which the HighPoint BIOS
-        * saves f_CNT value before  reprogramming the DPLL from its
-        * default setting (which differs for the various chips).
-        * NOTE: This register is only accessible via I/O space.
-        *
-        * In case the signature check fails, we'll have to resort to
-        * reading the f_CNT register itself in hopes that nobody has
-        * touched the DPLL yet...
+        * FIXME: Not portable. Also, why do we enable the ROM in the first place?
+        * We don't seem to be using it.
         */
-       temp = inl(pci_resource_start(dev, 4) + 0x90);
-       if ((temp & 0xFFFFF000) != 0xABCDE000) {
-               printk(KERN_WARNING "HPT37X: no clock data saved by BIOS\n");
-
-               /* Calculate the average value of f_CNT */
-               for (temp = i = 0; i < 128; i++) {
-                       pci_read_config_word(dev, 0x78, &freq);
-                       temp += freq & 0x1ff;
-                       mdelay(1);
-               }
-               freq = temp / 128;
-       } else
-               freq = temp & 0x1ff;
+       if (dev->resource[PCI_ROM_RESOURCE].start)
+               pci_write_config_dword(dev, PCI_ROM_ADDRESS,
+                       dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+
+       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+       pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+       pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
 
        /*
-        * HPT3xxN chips use different PCI clock information.
-        * Currently we always set up the PLL for them.
+        * First, try to estimate the PCI clock frequency...
         */
+       if (info->chip_type >= HPT370) {
+               u8  scr1  = 0;
+               u16 f_cnt = 0;
+               u32 temp  = 0;
 
-       if (info->flags & IS_3xxN) {
-               if(freq < 0x55)
-                       pll = F_LOW_PCI_33;
-               else if(freq < 0x70)
-                       pll = F_LOW_PCI_40;
-               else if(freq < 0x7F)
-                       pll = F_LOW_PCI_50;
-               else
-                       pll = F_LOW_PCI_66;
+               /* Interrupt force enable. */
+               pci_read_config_byte(dev, 0x5a, &scr1);
+               if (scr1 & 0x10)
+                       pci_write_config_byte(dev, 0x5a, scr1 & ~0x10);
 
-               printk(KERN_INFO "HPT3xxN detected, FREQ: %d, PLL: %d\n", freq, pll);
-       }
-       else
-       {
-               if(freq < 0x9C)
-                       pll = F_LOW_PCI_33;
-               else if(freq < 0xb0)
-                       pll = F_LOW_PCI_40;
-               else if(freq <0xc8)
-                       pll = F_LOW_PCI_50;
+               /*
+                * HighPoint does this for HPT372A.
+                * NOTE: This register is only writeable via I/O space.
+                */
+               if (info->chip_type == HPT372A)
+                       outb(0x0e, io_base + 0x9c);
+
+               /*
+                * Default to PCI clock. Make sure MA15/16 are set to output
+                * to prevent drives having problems with 40-pin cables.
+                */
+               pci_write_config_byte(dev, 0x5b, 0x23);
+
+               /*
+                * We'll have to read f_CNT value in order to determine
+                * the PCI clock frequency according to the following ratio:
+                *
+                * f_CNT = Fpci * 192 / Fdpll
+                *
+                * First try reading the register in which the HighPoint BIOS
+                * saves f_CNT value before  reprogramming the DPLL from its
+                * default setting (which differs for the various chips).
+                * NOTE: This register is only accessible via I/O space.
+                *
+                * In case the signature check fails, we'll have to resort to
+                * reading the f_CNT register itself in hopes that nobody has
+                * touched the DPLL yet...
+                */
+               temp = inl(io_base + 0x90);
+               if ((temp & 0xFFFFF000) != 0xABCDE000) {
+                       int i;
+
+                       printk(KERN_WARNING "%s: no clock data saved by BIOS\n",
+                              name);
+
+                       /* Calculate the average value of f_CNT. */
+                       for (temp = i = 0; i < 128; i++) {
+                               pci_read_config_word(dev, 0x78, &f_cnt);
+                               temp += f_cnt & 0x1ff;
+                               mdelay(1);
+                       }
+                       f_cnt = temp / 128;
+               } else
+                       f_cnt = temp & 0x1ff;
+
+               dpll_clk = info->dpll_clk;
+               pci_clk  = (f_cnt * dpll_clk) / 192;
+
+               /* Clamp PCI clock to bands. */
+               if (pci_clk < 40)
+                       pci_clk = 33;
+               else if(pci_clk < 45)
+                       pci_clk = 40;
+               else if(pci_clk < 55)
+                       pci_clk = 50;
                else
-                       pll = F_LOW_PCI_66;
-       
-               if (pll == F_LOW_PCI_33) {
-                       info->speed = thirty_three_base_hpt37x;
-                       printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n");
-               } else if (pll == F_LOW_PCI_40) {
-                       /* Unsupported */
-               } else if (pll == F_LOW_PCI_50) {
-                       info->speed = fifty_base_hpt37x;
-                       printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n");
-               } else {
-                       info->speed = sixty_six_base_hpt37x;
-                       printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n");
+                       pci_clk = 66;
+
+               printk(KERN_INFO "%s: DPLL base: %d MHz, f_CNT: %d, "
+                      "assuming %d MHz PCI\n", name, dpll_clk, f_cnt, pci_clk);
+       } else {
+               u32 itr1 = 0;
+
+               pci_read_config_dword(dev, 0x40, &itr1);
+
+               /* Detect PCI clock by looking at cmd_high_time. */
+               switch((itr1 >> 8) & 0x07) {
+                       case 0x09:
+                               pci_clk = 40;
+                               break;
+                       case 0x05:
+                               pci_clk = 25;
+                               break;
+                       case 0x07:
+                       default:
+                               pci_clk = 33;
+                               break;
                }
        }
 
-       if (pll == F_LOW_PCI_66)
-               info->flags |= PCI_66MHZ;
+       /* Let's assume we'll use PCI clock for the ATA clock... */
+       switch (pci_clk) {
+               case 25:
+                       clock = ATA_CLOCK_25MHZ;
+                       break;
+               case 33:
+               default:
+                       clock = ATA_CLOCK_33MHZ;
+                       break;
+               case 40:
+                       clock = ATA_CLOCK_40MHZ;
+                       break;
+               case 50:
+                       clock = ATA_CLOCK_50MHZ;
+                       break;
+               case 66:
+                       clock = ATA_CLOCK_66MHZ;
+                       break;
+       }
 
        /*
-        * only try the pll if we don't have a table for the clock
-        * speed that we're running at. NOTE: the internal PLL will
-        * result in slow reads when using a 33MHz PCI clock. we also
-        * don't like to use the PLL because it will cause glitches
-        * on PRST/SRST when the HPT state engine gets reset.
+        * Only try the DPLL if we don't have a table for the PCI clock that
+        * we are running at for HPT370/A, always use it  for anything newer...
         *
-        * ToDo: Use 66MHz PLL when ATA133 devices are present on a
-        * 372 device so we can get ATA133 support
+        * NOTE: Using the internal DPLL results in slow reads on 33 MHz PCI.
+        * We also  don't like using  the DPLL because this causes glitches
+        * on PRST-/SRST- when the state engine gets reset...
         */
-       if (info->speed)
-               goto init_hpt37X_done;
+       if (info->chip_type >= HPT374 || info->settings[clock] == NULL) {
+               u16 f_low, delta = pci_clk < 50 ? 2 : 4;
+               int adjust;
+
+                /*
+                 * Select 66 MHz DPLL clock only if UltraATA/133 mode is
+                 * supported/enabled, use 50 MHz DPLL clock otherwise...
+                 */
+               if (info->max_mode == 0x04) {
+                       dpll_clk = 66;
+                       clock = ATA_CLOCK_66MHZ;
+               } else if (dpll_clk) {  /* HPT36x chips don't have DPLL */
+                       dpll_clk = 50;
+                       clock = ATA_CLOCK_50MHZ;
+               }
 
-       info->flags |= PLL_MODE;
-       
-       /*
-        * Adjust the PLL based upon the PCI clock, enable it, and
-        * wait for stabilization...
-        */
-       adjust = 0;
-       freq = (pll < F_LOW_PCI_50) ? 2 : 4;
-       while (adjust++ < 6) {
-               pci_write_config_dword(dev, 0x5c, (freq + pll) << 16 |
-                                      pll | 0x100);
-
-               /* wait for clock stabilization */
-               for (i = 0; i < 0x50000; i++) {
-                       pci_read_config_byte(dev, 0x5b, &reg5bh);
-                       if (reg5bh & 0x80) {
-                               /* spin looking for the clock to destabilize */
-                               for (i = 0; i < 0x1000; ++i) {
-                                       pci_read_config_byte(dev, 0x5b, 
-                                                            &reg5bh);
-                                       if ((reg5bh & 0x80) == 0)
-                                               goto pll_recal;
-                               }
-                               pci_read_config_dword(dev, 0x5c, &pll);
-                               pci_write_config_dword(dev, 0x5c, 
-                                                      pll & ~0x100);
-                               pci_write_config_byte(dev, 0x5b, 0x21);
-
-                               info->speed = fifty_base_hpt37x;
-                               printk("HPT37X: using 50MHz internal PLL\n");
-                               goto init_hpt37X_done;
-                       }
+               if (info->settings[clock] == NULL) {
+                       printk(KERN_ERR "%s: unknown bus timing!\n", name);
+                       kfree(info);
+                       return -EIO;
                }
-pll_recal:
-               if (adjust & 1)
-                       pll -= (adjust >> 1);
-               else
-                       pll += (adjust >> 1);
-       } 
 
-init_hpt37X_done:
-       if (!info->speed)
-               printk(KERN_ERR "HPT37x%s: unknown bus timing [%d %d].\n",
-                      (info->flags & IS_3xxN) ? "N" : "", pll, freq);
-       /*
-        * Reset the state engines.
-        * NOTE: avoid accidentally enabling the primary channel on HPT371N.
-        */
-       pci_read_config_byte(dev, 0x50, &mcr1);
-       if (mcr1 & 0x04)
-               pci_write_config_byte(dev, 0x50, 0x37);
-       pci_write_config_byte(dev, 0x54, 0x37);
-       udelay(100);
-}
+               /* Select the DPLL clock. */
+               pci_write_config_byte(dev, 0x5b, 0x21);
 
-static int __devinit init_hpt37x(struct pci_dev *dev)
-{
-       u8 reg5ah;
+               /*
+                * Adjust the DPLL based upon PCI clock, enable it,
+                * and wait for stabilization...
+                */
+               f_low = (pci_clk * 48) / dpll_clk;
 
-       pci_read_config_byte(dev, 0x5a, &reg5ah);
-       /* interrupt force enable */
-       pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
-       return 0;
-}
+               for (adjust = 0; adjust < 8; adjust++) {
+                       if(hpt37x_calibrate_dpll(dev, f_low, f_low + delta))
+                               break;
 
-static int __devinit init_hpt366(struct pci_dev *dev)
-{
-       u32 reg1        = 0;
-       u8 drive_fast   = 0;
+                       /*
+                        * See if it'll settle at a fractionally different clock
+                        */
+                       if (adjust & 1)
+                               f_low -= adjust >> 1;
+                       else
+                               f_low += adjust >> 1;
+               }
+               if (adjust == 8) {
+                       printk(KERN_ERR "%s: DPLL did not stabilize!\n", name);
+                       kfree(info);
+                       return -EIO;
+               }
 
-       /*
-        * Disable the "fast interrupt" prediction.
-        */
-       pci_read_config_byte(dev, 0x51, &drive_fast);
-       if (drive_fast & 0x80)
-               pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
-       pci_read_config_dword(dev, 0x40, &reg1);
-                                                                       
-       return 0;
-}
+               printk("%s: using %d MHz DPLL clock\n", name, dpll_clk);
+       } else {
+               /* Mark the fact that we're not using the DPLL. */
+               dpll_clk = 0;
 
-static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
-{
-       int ret = 0;
+               printk("%s: using %d MHz PCI clock\n", name, pci_clk);
+       }
 
        /*
-        * FIXME: Not portable. Also, why do we enable the ROM in the first place?
-        * We don't seem to be using it.
+        * Advance the table pointer to a slot which points to the list
+        * of the register values settings matching the clock being used.
         */
-       if (dev->resource[PCI_ROM_RESOURCE].start)
-               pci_write_config_dword(dev, PCI_ROM_ADDRESS,
-                       dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
+       info->settings += clock;
 
-       pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
-       pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
-       pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
-       pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
+       /* Store the clock frequencies. */
+       info->dpll_clk  = dpll_clk;
+       info->pci_clk   = pci_clk;
 
-       if (hpt_revision(dev) >= 3)
-               ret = init_hpt37x(dev);
-       else
-               ret = init_hpt366(dev);
+       /* Point to this chip's own instance of the hpt_info structure. */
+       pci_set_drvdata(dev, info);
 
-       if (ret)
-               return ret;
+       if (info->chip_type >= HPT370) {
+               u8  mcr1, mcr4;
+
+               /*
+                * Reset the state engines.
+                * NOTE: Avoid accidentally enabling the disabled channels.
+                */
+               pci_read_config_byte (dev, 0x50, &mcr1);
+               pci_read_config_byte (dev, 0x54, &mcr4);
+               pci_write_config_byte(dev, 0x50, (mcr1 | 0x32));
+               pci_write_config_byte(dev, 0x54, (mcr4 | 0x32));
+               udelay(100);
+       }
+
+       /*
+        * On  HPT371N, if ATA clock is 66 MHz we must set bit 2 in
+        * the MISC. register to stretch the UltraDMA Tss timing.
+        * NOTE: This register is only writeable via I/O space.
+        */
+       if (info->chip_type == HPT371N && clock == ATA_CLOCK_66MHZ)
+
+               outb(inb(io_base + 0x9c) | 0x04, io_base + 0x9c);
 
        return dev->irq;
 }
 
 static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
 {
-       struct pci_dev *dev             = hwif->pci_dev;
-       struct hpt_info *info           = ide_get_hwifdata(hwif);
-       u8 ata66 = 0, regmask           = (hwif->channel) ? 0x01 : 0x02;
+       struct pci_dev  *dev            = hwif->pci_dev;
+       struct hpt_info *info           = pci_get_drvdata(dev);
        int serialize                   = HPT_SERIALIZE_IO;
-       
+       u8  scr1 = 0, ata66             = (hwif->channel) ? 0x01 : 0x02;
+       u8  chip_type                   = info->chip_type;
+       u8  new_mcr, old_mcr            = 0;
+
+       /* Cache the channel's MISC. control registers' offset */
+       hwif->select_data               = hwif->channel ? 0x54 : 0x50;
+
        hwif->tuneproc                  = &hpt3xx_tune_drive;
        hwif->speedproc                 = &hpt3xx_tune_chipset;
        hwif->quirkproc                 = &hpt3xx_quirkproc;
        hwif->intrproc                  = &hpt3xx_intrproc;
        hwif->maskproc                  = &hpt3xx_maskproc;
-       
+       hwif->busproc                   = &hpt3xx_busproc;
+
        /*
         * HPT3xxN chips have some complications:
         *
         * - on 33 MHz PCI we must clock switch
         * - on 66 MHz PCI we must NOT use the PCI clock
         */
-       if ((info->flags & (IS_3xxN | PCI_66MHZ)) == IS_3xxN) {
+       if (chip_type >= HPT372N && info->dpll_clk && info->pci_clk < 66) {
                /*
                 * Clock is shared between the channels,
                 * so we'll have to serialize them... :-(
@@ -1250,200 +1295,171 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
                hwif->rw_disk = &hpt3xxn_rw_disk;
        }
 
+       /* Serialize access to this device if needed */
+       if (serialize && hwif->mate)
+               hwif->serialized = hwif->mate->serialized = 1;
+
+       /*
+        * Disable the "fast interrupt" prediction.  Don't hold off
+        * on interrupts. (== 0x01 despite what the docs say)
+        */
+       pci_read_config_byte(dev, hwif->select_data + 1, &old_mcr);
+
+       if (info->chip_type >= HPT374)
+               new_mcr = old_mcr & ~0x07;
+       else if (info->chip_type >= HPT370) {
+               new_mcr = old_mcr;
+               new_mcr &= ~0x02;
+
+#ifdef HPT_DELAY_INTERRUPT
+               new_mcr &= ~0x01;
+#else
+               new_mcr |=  0x01;
+#endif
+       } else                                  /* HPT366 and HPT368  */
+               new_mcr = old_mcr & ~0x80;
+
+       if (new_mcr != old_mcr)
+               pci_write_config_byte(dev, hwif->select_data + 1, new_mcr);
+
+       if (!hwif->dma_base) {
+               hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+               return;
+       }
+
+       hwif->ultra_mask = 0x7f;
+       hwif->mwdma_mask = 0x07;
+
        /*
         * The HPT37x uses the CBLID pins as outputs for MA15/MA16
-        * address lines to access an external eeprom.  To read valid
+        * address lines to access an external EEPROM.  To read valid
         * cable detect state the pins must be enabled as inputs.
         */
-       if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) {
+       if (chip_type == HPT374 && (PCI_FUNC(dev->devfn) & 1)) {
                /*
                 * HPT374 PCI function 1
                 * - set bit 15 of reg 0x52 to enable TCBLID as input
                 * - set bit 15 of reg 0x56 to enable FCBLID as input
                 */
-               u16 mcr3, mcr6;
-               pci_read_config_word(dev, 0x52, &mcr3);
-               pci_read_config_word(dev, 0x56, &mcr6);
-               pci_write_config_word(dev, 0x52, mcr3 | 0x8000);
-               pci_write_config_word(dev, 0x56, mcr6 | 0x8000);
+               u8  mcr_addr = hwif->select_data + 2;
+               u16 mcr;
+
+               pci_read_config_word (dev, mcr_addr, &mcr);
+               pci_write_config_word(dev, mcr_addr, (mcr | 0x8000));
                /* now read cable id register */
-               pci_read_config_byte(dev, 0x5a, &ata66);
-               pci_write_config_word(dev, 0x52, mcr3);
-               pci_write_config_word(dev, 0x56, mcr6);
-       } else if (info->revision >= 3) {
+               pci_read_config_byte (dev, 0x5a, &scr1);
+               pci_write_config_word(dev, mcr_addr, mcr);
+       } else if (chip_type >= HPT370) {
                /*
                 * HPT370/372 and 374 pcifn 0
-                * - clear bit 0 of 0x5b to enable P/SCBLID as inputs
+                * - clear bit 0 of reg 0x5b to enable P/SCBLID as inputs
                 */
-               u8 scr2;
-               pci_read_config_byte(dev, 0x5b, &scr2);
-               pci_write_config_byte(dev, 0x5b, scr2 & ~1);
-               /* now read cable id register */
-               pci_read_config_byte(dev, 0x5a, &ata66);
-               pci_write_config_byte(dev, 0x5b, scr2);
-       } else {
-               pci_read_config_byte(dev, 0x5a, &ata66);
-       }
+               u8 scr2 = 0;
 
-#ifdef DEBUG
-       printk("HPT366: reg5ah=0x%02x ATA-%s Cable Port%d\n",
-               ata66, (ata66 & regmask) ? "33" : "66",
-               PCI_FUNC(hwif->pci_dev->devfn));
-#endif /* DEBUG */
-
-       /* Serialize access to this device */
-       if (serialize && hwif->mate)
-               hwif->serialized = hwif->mate->serialized = 1;
+               pci_read_config_byte (dev, 0x5b, &scr2);
+               pci_write_config_byte(dev, 0x5b, (scr2 & ~1));
+               /* now read cable id register */
+               pci_read_config_byte (dev, 0x5a, &scr1);
+               pci_write_config_byte(dev, 0x5b,  scr2);
+       } else
+               pci_read_config_byte (dev, 0x5a, &scr1);
 
-       /*
-        * Set up ioctl for power status.
-        * NOTE:  power affects both drives on each channel.
-        */
-       hwif->busproc = &hpt3xx_busproc;
+       if (!hwif->udma_four)
+               hwif->udma_four = (scr1 & ata66) ? 0 : 1;
 
-       if (!hwif->dma_base) {
-               hwif->drives[0].autotune = 1;
-               hwif->drives[1].autotune = 1;
-               return;
-       }
+       hwif->ide_dma_check             = &hpt366_config_drive_xfer_rate;
 
-       hwif->ultra_mask = 0x7f;
-       hwif->mwdma_mask = 0x07;
-
-       if (!(hwif->udma_four))
-               hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
-       hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
-
-       if (info->revision >= 8) {
-               hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
-               hwif->ide_dma_end = &hpt374_ide_dma_end;
-       } else if (info->revision >= 5) {
-               hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
-               hwif->ide_dma_end = &hpt374_ide_dma_end;
-       } else if (info->revision >= 3) {
-               hwif->dma_start = &hpt370_ide_dma_start;
-               hwif->ide_dma_end = &hpt370_ide_dma_end;
-               hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
-               hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
-       } else if (info->revision >= 2)
-               hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
-       else
-               hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
+       if (chip_type >= HPT374) {
+               hwif->ide_dma_test_irq  = &hpt374_ide_dma_test_irq;
+               hwif->ide_dma_end       = &hpt374_ide_dma_end;
+       } else if (chip_type >= HPT370) {
+               hwif->dma_start         = &hpt370_ide_dma_start;
+               hwif->ide_dma_end       = &hpt370_ide_dma_end;
+               hwif->ide_dma_timeout   = &hpt370_ide_dma_timeout;
+       } else
+               hwif->ide_dma_lostirq   = &hpt366_ide_dma_lostirq;
 
        if (!noautodma)
                hwif->autodma = 1;
-       hwif->drives[0].autodma = hwif->autodma;
-       hwif->drives[1].autodma = hwif->autodma;
+       hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
 }
 
 static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
 {
-       struct hpt_info *info   = ide_get_hwifdata(hwif);
-       u8 masterdma    = 0, slavedma = 0;
-       u8 dma_new      = 0, dma_old = 0;
-       u8 primary      = hwif->channel ? 0x4b : 0x43;
-       u8 secondary    = hwif->channel ? 0x4f : 0x47;
+       struct pci_dev  *dev            = hwif->pci_dev;
+       u8 masterdma    = 0, slavedma   = 0;
+       u8 dma_new      = 0, dma_old    = 0;
        unsigned long flags;
 
        if (!dmabase)
                return;
                
-       if(info->speed == NULL) {
-               printk(KERN_WARNING "hpt366: no known IDE timings, disabling DMA.\n");
-               return;
-       }
-
-       dma_old = hwif->INB(dmabase+2);
+       dma_old = hwif->INB(dmabase + 2);
 
        local_irq_save(flags);
 
        dma_new = dma_old;
-       pci_read_config_byte(hwif->pci_dev, primary, &masterdma);
-       pci_read_config_byte(hwif->pci_dev, secondary, &slavedma);
+       pci_read_config_byte(dev, hwif->channel ? 0x4b : 0x43, &masterdma);
+       pci_read_config_byte(dev, hwif->channel ? 0x4f : 0x47,  &slavedma);
 
        if (masterdma & 0x30)   dma_new |= 0x20;
-       if (slavedma & 0x30)    dma_new |= 0x40;
+       if ( slavedma & 0x30)   dma_new |= 0x40;
        if (dma_new != dma_old)
-               hwif->OUTB(dma_new, dmabase+2);
+               hwif->OUTB(dma_new, dmabase + 2);
 
        local_irq_restore(flags);
 
        ide_setup_dma(hwif, dmabase, 8);
 }
 
-/*
- *     We "borrow" this hook in order to set the data structures
- *     up early enough before dma or init_hwif calls are made.
- */
-
-static void __devinit init_iops_hpt366(ide_hwif_t *hwif)
-{
-       struct hpt_info *info   = kzalloc(sizeof(struct hpt_info), GFP_KERNEL);
-       struct pci_dev  *dev    = hwif->pci_dev;
-       u16 did                 = dev->device;
-       u8  rid                 = 0;
-
-       if(info == NULL) {
-               printk(KERN_WARNING "hpt366: out of memory.\n");
-               return;
-       }
-       ide_set_hwifdata(hwif, info);
-
-       /* Avoid doing the same thing twice. */
-       if (hwif->channel && hwif->mate) {
-               memcpy(info, ide_get_hwifdata(hwif->mate), sizeof(struct hpt_info));
-               return;
-       }
-
-       pci_read_config_byte(dev, PCI_CLASS_REVISION, &rid);
-
-       if (( did == PCI_DEVICE_ID_TTI_HPT366  && rid == 6) ||
-           ((did == PCI_DEVICE_ID_TTI_HPT372  ||
-             did == PCI_DEVICE_ID_TTI_HPT302  ||
-             did == PCI_DEVICE_ID_TTI_HPT371) && rid > 1) ||
-             did == PCI_DEVICE_ID_TTI_HPT372N)
-               info->flags |= IS_3xxN;
-
-       info->revision = hpt_revision(dev);
-
-       if (info->revision >= 3)
-               hpt37x_clocking(hwif);
-       else
-               hpt366_clocking(hwif);
-}
-
 static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
 {
-       struct pci_dev *findev = NULL;
+       struct pci_dev *dev2;
 
        if (PCI_FUNC(dev->devfn) & 1)
                return -ENODEV;
 
-       while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
-               if ((findev->vendor == dev->vendor) &&
-                   (findev->device == dev->device) &&
-                   ((findev->devfn - dev->devfn) == 1) &&
-                   (PCI_FUNC(findev->devfn) & 1)) {
-                       if (findev->irq != dev->irq) {
-                               /* FIXME: we need a core pci_set_interrupt() */
-                               findev->irq = dev->irq;
-                               printk(KERN_WARNING "%s: pci-config space interrupt "
-                                       "fixed.\n", d->name);
-                       }
-                       return ide_setup_pci_devices(dev, findev, d);
+       pci_set_drvdata(dev, &hpt374);
+
+       if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
+               int ret;
+
+               pci_set_drvdata(dev2, &hpt374);
+
+               if (dev2->irq != dev->irq) {
+                       /* FIXME: we need a core pci_set_interrupt() */
+                       dev2->irq = dev->irq;
+                       printk(KERN_WARNING "%s: PCI config space interrupt "
+                              "fixed.\n", d->name);
                }
+               ret = ide_setup_pci_devices(dev, dev2, d);
+               if (ret < 0)
+                       pci_dev_put(dev2);
+               return ret;
        }
        return ide_setup_pci_device(dev, d);
 }
 
-static int __devinit init_setup_hpt37x(struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit init_setup_hpt372n(struct pci_dev *dev, ide_pci_device_t *d)
 {
+       pci_set_drvdata(dev, &hpt372n);
+
        return ide_setup_pci_device(dev, d);
 }
 
 static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
 {
-       u8 mcr1 = 0;
+       struct hpt_info *info;
+       u8 rev = 0, mcr1 = 0;
+
+       pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+       if (rev > 1) {
+               d->name = "HPT371N";
+
+               info = &hpt371n;
+       } else
+               info = &hpt371;
 
        /*
         * HPT371 chips physically have only one channel, the secondary one,
@@ -1453,59 +1469,94 @@ static int __devinit init_setup_hpt371(struct pci_dev *dev, ide_pci_device_t *d)
         */
        pci_read_config_byte(dev, 0x50, &mcr1);
        if (mcr1 & 0x04)
-               pci_write_config_byte(dev, 0x50, (mcr1 & ~0x04));
+               pci_write_config_byte(dev, 0x50, mcr1 & ~0x04);
+
+       pci_set_drvdata(dev, info);
+
+       return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_hpt372a(struct pci_dev *dev, ide_pci_device_t *d)
+{
+       struct hpt_info *info;
+       u8 rev = 0;
+
+       pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+       if (rev > 1) {
+               d->name = "HPT372N";
+
+               info = &hpt372n;
+       } else
+               info = &hpt372a;
+       pci_set_drvdata(dev, info);
+
+       return ide_setup_pci_device(dev, d);
+}
+
+static int __devinit init_setup_hpt302(struct pci_dev *dev, ide_pci_device_t *d)
+{
+       struct hpt_info *info;
+       u8 rev = 0;
+
+       pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
+
+       if (rev > 1) {
+               d->name = "HPT302N";
+
+               info = &hpt302n;
+       } else
+               info = &hpt302;
+       pci_set_drvdata(dev, info);
 
        return ide_setup_pci_device(dev, d);
 }
 
 static int __devinit init_setup_hpt366(struct pci_dev *dev, ide_pci_device_t *d)
 {
-       struct pci_dev *findev = NULL;
-       u8 pin1 = 0, pin2 = 0;
-       unsigned int class_rev;
-       char *chipset_names[] = {"HPT366", "HPT366",  "HPT368",
-                                "HPT370", "HPT370A", "HPT372",
-                                "HPT372N" };
+       struct pci_dev *dev2;
+       u8 rev = 0;
+       static char   *chipset_names[] = { "HPT366", "HPT366",  "HPT368",
+                                          "HPT370", "HPT370A", "HPT372",
+                                          "HPT372N" };
+       static struct hpt_info *info[] = { &hpt36x,  &hpt36x,  &hpt36x,
+                                          &hpt370,  &hpt370a, &hpt372,
+                                          &hpt372n  };
 
        if (PCI_FUNC(dev->devfn) & 1)
                return -ENODEV;
 
-       pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
-       class_rev &= 0xff;
+       pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
 
-       if(dev->device == PCI_DEVICE_ID_TTI_HPT372N)
-               class_rev = 6;
+       if (rev > 6)
+               rev = 6;
                
-       if(class_rev <= 6)
-               d->name = chipset_names[class_rev];
-
-       switch(class_rev) {
-               case 6:
-               case 5:
-               case 4:
-               case 3:
-                       goto init_single;
-               default:
-                       break;
-       }
+       d->name = chipset_names[rev];
+
+       pci_set_drvdata(dev, info[rev]);
+
+       if (rev > 2)
+               goto init_single;
 
        d->channels = 1;
 
-       pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1);
-       while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) {
-               if ((findev->vendor == dev->vendor) &&
-                   (findev->device == dev->device) &&
-                   ((findev->devfn - dev->devfn) == 1) &&
-                   (PCI_FUNC(findev->devfn) & 1)) {
-                       pci_read_config_byte(findev, PCI_INTERRUPT_PIN, &pin2);
-                       if ((pin1 != pin2) && (dev->irq == findev->irq)) {
-                               d->bootable = ON_BOARD;
-                               printk("%s: onboard version of chipset, "
-                                       "pin1=%d pin2=%d\n", d->name,
-                                       pin1, pin2);
-                       }
-                       return ide_setup_pci_devices(dev, findev, d);
+       if ((dev2 = pci_get_slot(dev->bus, dev->devfn + 1)) != NULL) {
+               u8  pin1 = 0, pin2 = 0;
+               int ret;
+
+               pci_set_drvdata(dev2, info[rev]);
+
+               pci_read_config_byte(dev,  PCI_INTERRUPT_PIN, &pin1);
+               pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin2);
+               if (pin1 != pin2 && dev->irq == dev2->irq) {
+                       d->bootable = ON_BOARD;
+                       printk("%s: onboard version of chipset, pin1=%d pin2=%d\n",
+                              d->name, pin1, pin2);
                }
+               ret = ide_setup_pci_devices(dev, dev2, d);
+               if (ret < 0)
+                       pci_dev_put(dev2);
+               return ret;
        }
 init_single:
        return ide_setup_pci_device(dev, d);
@@ -1516,64 +1567,68 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
                .name           = "HPT366",
                .init_setup     = init_setup_hpt366,
                .init_chipset   = init_chipset_hpt366,
-               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,
                .autodma        = AUTODMA,
+               .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .bootable       = OFF_BOARD,
                .extra          = 240
        },{     /* 1 */
                .name           = "HPT372A",
-               .init_setup     = init_setup_hpt37x,
+               .init_setup     = init_setup_hpt372a,
                .init_chipset   = init_chipset_hpt366,
-               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,
                .autodma        = AUTODMA,
+               .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .bootable       = OFF_BOARD,
+               .extra          = 240
        },{     /* 2 */
                .name           = "HPT302",
-               .init_setup     = init_setup_hpt37x,
+               .init_setup     = init_setup_hpt302,
                .init_chipset   = init_chipset_hpt366,
-               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,
                .autodma        = AUTODMA,
+               .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .bootable       = OFF_BOARD,
+               .extra          = 240
        },{     /* 3 */
                .name           = "HPT371",
                .init_setup     = init_setup_hpt371,
                .init_chipset   = init_chipset_hpt366,
-               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,
                .autodma        = AUTODMA,
                .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .bootable       = OFF_BOARD,
+               .extra          = 240
        },{     /* 4 */
                .name           = "HPT374",
                .init_setup     = init_setup_hpt374,
                .init_chipset   = init_chipset_hpt366,
-               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,    /* 4 */
                .autodma        = AUTODMA,
+               .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .bootable       = OFF_BOARD,
+               .extra          = 240
        },{     /* 5 */
                .name           = "HPT372N",
-               .init_setup     = init_setup_hpt37x,
+               .init_setup     = init_setup_hpt372n,
                .init_chipset   = init_chipset_hpt366,
-               .init_iops      = init_iops_hpt366,
                .init_hwif      = init_hwif_hpt366,
                .init_dma       = init_dma_hpt366,
                .channels       = 2,    /* 4 */
                .autodma        = AUTODMA,
+               .enablebits     = {{0x50,0x04,0x04}, {0x54,0x04,0x04}},
                .bootable       = OFF_BOARD,
+               .extra          = 240
        }
 };
 
diff --git a/drivers/ide/pci/it8213.c b/drivers/ide/pci/it8213.c
new file mode 100644 (file)
index 0000000..63248b6
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * ITE 8213 IDE driver
+ *
+ * Copyright (C) 2006 Jack Lee
+ * Copyright (C) 2006 Alan Cox
+ * Copyright (C) 2007 Bartlomiej Zolnierkiewicz
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+/*
+ *     it8213_ratemask -       Compute available modes
+ *     @drive: IDE drive
+ *
+ *     Compute the available speeds for the devices on the interface. This
+ *     is all modes to ATA133 clipped by drive cable setup.
+ */
+
+static u8 it8213_ratemask (ide_drive_t *drive)
+{
+       u8 mode = 4;
+       if (!eighty_ninty_three(drive))
+               mode = min_t(u8, mode, 1);
+       return mode;
+}
+
+/**
+ *     it8213_dma_2_pio                -       return the PIO mode matching DMA
+ *     @xfer_rate: transfer speed
+ *
+ *     Returns the nearest equivalent PIO timing for the PIO or DMA
+ *     mode requested by the controller.
+ */
+
+static u8 it8213_dma_2_pio (u8 xfer_rate) {
+       switch(xfer_rate) {
+               case XFER_UDMA_6:
+               case XFER_UDMA_5:
+               case XFER_UDMA_4:
+               case XFER_UDMA_3:
+               case XFER_UDMA_2:
+               case XFER_UDMA_1:
+               case XFER_UDMA_0:
+               case XFER_MW_DMA_2:
+               case XFER_PIO_4:
+                       return 4;
+               case XFER_MW_DMA_1:
+               case XFER_PIO_3:
+                       return 3;
+               case XFER_SW_DMA_2:
+               case XFER_PIO_2:
+                       return 2;
+               case XFER_MW_DMA_0:
+               case XFER_SW_DMA_1:
+               case XFER_SW_DMA_0:
+               case XFER_PIO_1:
+               case XFER_PIO_0:
+               case XFER_PIO_SLOW:
+               default:
+                       return 0;
+       }
+}
+
+/*
+ *     it8213_tuneproc -       tune a drive
+ *     @drive: drive to tune
+ *     @pio: desired PIO mode
+ *
+ *     Set the interface PIO mode.
+ */
+
+static void it8213_tuneproc (ide_drive_t *drive, u8 pio)
+{
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
+       int is_slave            = drive->dn & 1;
+       int master_port         = 0x40;
+       int slave_port          = 0x44;
+       unsigned long flags;
+       u16 master_data;
+       u8 slave_data;
+       static DEFINE_SPINLOCK(tune_lock);
+       int control = 0;
+
+       static const u8 timings[][2]= {
+                                       { 0, 0 },
+                                       { 0, 0 },
+                                       { 1, 0 },
+                                       { 2, 1 },
+                                       { 2, 3 }, };
+
+       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
+
+       spin_lock_irqsave(&tune_lock, flags);
+       pci_read_config_word(dev, master_port, &master_data);
+
+       if (pio > 1)
+               control |= 1;   /* Programmable timing on */
+       if (drive->media != ide_disk)
+               control |= 4;   /* ATAPI */
+       if (pio > 2)
+               control |= 2;   /* IORDY */
+       if (is_slave) {
+               master_data |=  0x4000;
+               master_data &= ~0x0070;
+               if (pio > 1)
+                       master_data = master_data | (control << 4);
+               pci_read_config_byte(dev, slave_port, &slave_data);
+               slave_data = slave_data & 0xf0;
+               slave_data = slave_data | (timings[pio][0] << 2) | timings[pio][1];
+       } else {
+               master_data &= ~0x3307;
+               if (pio > 1)
+                       master_data = master_data | control;
+               master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
+       }
+       pci_write_config_word(dev, master_port, master_data);
+       if (is_slave)
+               pci_write_config_byte(dev, slave_port, slave_data);
+       spin_unlock_irqrestore(&tune_lock, flags);
+}
+
+/**
+ *     it8213_tune_chipset     -       set controller timings
+ *     @drive: Drive to set up
+ *     @xferspeed: speed we want to achieve
+ *
+ *     Tune the ITE chipset for the desired mode. If we can't achieve
+ *     the desired mode then tune for a lower one, but ultimately
+ *     make the thing work.
+ */
+
+static int it8213_tune_chipset (ide_drive_t *drive, u8 xferspeed)
+{
+
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct pci_dev *dev     = hwif->pci_dev;
+       u8 maslave              = 0x40;
+       u8 speed                = ide_rate_filter(it8213_ratemask(drive), xferspeed);
+       int a_speed             = 3 << (drive->dn * 4);
+       int u_flag              = 1 << drive->dn;
+       int v_flag              = 0x01 << drive->dn;
+       int w_flag              = 0x10 << drive->dn;
+       int u_speed             = 0;
+       u16                     reg4042, reg4a;
+       u8                      reg48, reg54, reg55;
+
+       pci_read_config_word(dev, maslave, &reg4042);
+       pci_read_config_byte(dev, 0x48, &reg48);
+       pci_read_config_word(dev, 0x4a, &reg4a);
+       pci_read_config_byte(dev, 0x54, &reg54);
+       pci_read_config_byte(dev, 0x55, &reg55);
+
+       switch(speed) {
+               case XFER_UDMA_6:
+               case XFER_UDMA_4:
+               case XFER_UDMA_2:       u_speed = 2 << (drive->dn * 4); break;
+               case XFER_UDMA_5:
+               case XFER_UDMA_3:
+               case XFER_UDMA_1:       u_speed = 1 << (drive->dn * 4); break;
+               case XFER_UDMA_0:       u_speed = 0 << (drive->dn * 4); break;
+                       break;
+               case XFER_MW_DMA_2:
+               case XFER_MW_DMA_1:
+               case XFER_SW_DMA_2:
+                       break;
+               case XFER_PIO_4:
+               case XFER_PIO_3:
+               case XFER_PIO_2:
+               case XFER_PIO_1:
+               case XFER_PIO_0:
+                       break;
+               default:
+                       return -1;
+       }
+
+       if (speed >= XFER_UDMA_0) {
+               if (!(reg48 & u_flag))
+                       pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+               if (speed >= XFER_UDMA_5) {
+                       pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+               } else {
+                       pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+               }
+
+               if ((reg4a & a_speed) != u_speed)
+                       pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
+               if (speed > XFER_UDMA_2) {
+                       if (!(reg54 & v_flag))
+                               pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+               } else
+                       pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+       } else {
+               if (reg48 & u_flag)
+                       pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+               if (reg4a & a_speed)
+                       pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+               if (reg54 & v_flag)
+                       pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+               if (reg55 & w_flag)
+                       pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+       }
+       it8213_tuneproc(drive, it8213_dma_2_pio(speed));
+       return ide_config_drive_speed(drive, speed);
+}
+
+/*
+ *     config_chipset_for_dma  -       configure for DMA
+ *     @drive: drive to configure
+ *
+ *     Called by the IDE layer when it wants the timings set up.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+       u8 speed = ide_dma_speed(drive, it8213_ratemask(drive));
+
+       if (!speed)
+               return 0;
+
+       it8213_tune_chipset(drive, speed);
+
+       return ide_dma_enable(drive);
+}
+
+/**
+ *     it8213_configure_drive_for_dma  -       set up for DMA transfers
+ *     @drive: drive we are going to set up
+ *
+ *     Set up the drive for DMA, tune the controller and drive as
+ *     required. If the drive isn't suitable for DMA or we hit
+ *     other problems then we will drop down to PIO and set up
+ *     PIO appropriately
+ */
+
+static int it8213_config_drive_for_dma (ide_drive_t *drive)
+{
+       ide_hwif_t *hwif = drive->hwif;
+
+       if (ide_use_dma(drive)) {
+               if (config_chipset_for_dma(drive))
+                       return hwif->ide_dma_on(drive);
+       }
+
+       hwif->speedproc(drive, XFER_PIO_0
+                       + ide_get_best_pio_mode(drive, 255, 4, NULL));
+
+       return hwif->ide_dma_off_quietly(drive);
+}
+
+/**
+ *     init_hwif_it8213        -       set up hwif structs
+ *     @hwif: interface to set up
+ *
+ *     We do the basic set up of the interface structure. The IT8212
+ *     requires several custom handlers so we override the default
+ *     ide DMA handlers appropriately
+ */
+
+static void __devinit init_hwif_it8213(ide_hwif_t *hwif)
+{
+       u8 reg42h = 0, ata66 = 0;
+
+       hwif->speedproc = &it8213_tune_chipset;
+       hwif->tuneproc  = &it8213_tuneproc;
+
+       hwif->autodma = 0;
+
+       hwif->drives[0].autotune = 1;
+       hwif->drives[1].autotune = 1;
+
+       if (!hwif->dma_base)
+               return;
+
+       hwif->atapi_dma = 1;
+       hwif->ultra_mask = 0x7f;
+       hwif->mwdma_mask = 0x06;
+       hwif->swdma_mask = 0x04;
+
+       pci_read_config_byte(hwif->pci_dev, 0x42, &reg42h);
+       ata66 = (reg42h & 0x02) ? 0 : 1;
+
+       hwif->ide_dma_check = &it8213_config_drive_for_dma;
+       if (!(hwif->udma_four))
+               hwif->udma_four = ata66;
+
+       /*
+        *      The BIOS often doesn't set up DMA on this controller
+        *      so we always do it.
+        */
+       if (!noautodma)
+               hwif->autodma = 1;
+
+       hwif->drives[0].autodma = hwif->autodma;
+       hwif->drives[1].autodma = hwif->autodma;
+}
+
+
+#define DECLARE_ITE_DEV(name_str)                      \
+       {                                               \
+               .name           = name_str,             \
+               .init_hwif      = init_hwif_it8213,     \
+               .channels       = 1,                    \
+               .autodma        = AUTODMA,              \
+               .enablebits     = {{0x41,0x80,0x80}}, \
+               .bootable       = ON_BOARD,             \
+       }
+
+static ide_pci_device_t it8213_chipsets[] __devinitdata = {
+       /* 0 */ DECLARE_ITE_DEV("IT8213"),
+};
+
+
+/**
+ *     it8213_init_one -       pci layer discovery entry
+ *     @dev: PCI device
+ *     @id: ident table entry
+ *
+ *     Called by the PCI code when it finds an ITE8213 controller. As
+ *     this device follows the standard interfaces we can use the
+ *     standard helper functions to do almost all the work for us.
+ */
+
+static int __devinit it8213_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+       ide_setup_pci_device(dev, &it8213_chipsets[id->driver_data]);
+       return 0;
+}
+
+
+static struct pci_device_id it8213_pci_tbl[] = {
+       { PCI_VENDOR_ID_ITE, 0x8213, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, it8213_pci_tbl);
+
+static struct pci_driver driver = {
+       .name           = "ITE8213_IDE",
+       .id_table       = it8213_pci_tbl,
+       .probe          = it8213_init_one,
+};
+
+static int __init it8213_ide_init(void)
+{
+       return ide_pci_register_driver(&driver);
+}
+
+module_init(it8213_ide_init);
+
+MODULE_AUTHOR("Jack Lee, Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the ITE 8213");
+MODULE_LICENSE("GPL");
index 77a9aaa..236a031 100644 (file)
@@ -92,26 +92,6 @@ static u8 pdcnew_ratemask(ide_drive_t *drive)
        return  mode;
 }
 
-static int check_in_drive_lists(ide_drive_t *drive, const char **list)
-{
-       struct hd_driveid *id = drive->id;
-
-       if (pdc_quirk_drives == list) {
-               while (*list) {
-                       if (strstr(id->model, *list++)) {
-                               return 2;
-                       }
-               }
-       } else {
-               while (*list) {
-                       if (!strcmp(*list++,id->model)) {
-                               return 1;
-                       }
-               }
-       }
-       return 0;
-}
-
 /**
  * get_indexed_reg - Get indexed register
  * @hwif: for the port address
@@ -249,13 +229,6 @@ static int pdcnew_tune_chipset(ide_drive_t *drive, u8 speed)
        return err;
 }
 
-/*   0    1    2    3    4    5    6   7   8
- * 960, 480, 390, 300, 240, 180, 120, 90, 60
- *           180, 150, 120,  90,  60
- * DMA_Speed
- * 180, 120,  90,  90,  90,  60,  30
- *  11,   5,   4,   3,   2,   1,   0
- */
 static void pdcnew_tune_drive(ide_drive_t *drive, u8 pio)
 {
        pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
@@ -313,12 +286,10 @@ static int pdcnew_config_drive_xfer_rate(ide_drive_t *drive)
 
        drive->init_speed = 0;
 
-       if (id && (id->capability & 1) && drive->autodma) {
+       if ((id->capability & 1) && drive->autodma) {
 
-               if (ide_use_dma(drive)) {
-                       if (config_chipset_for_dma(drive))
-                               return hwif->ide_dma_on(drive);
-               }
+               if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+                       return hwif->ide_dma_on(drive);
 
                goto fast_ata_pio;
 
@@ -333,21 +304,12 @@ fast_ata_pio:
 
 static int pdcnew_quirkproc(ide_drive_t *drive)
 {
-       return check_in_drive_lists(drive, pdc_quirk_drives);
-}
+       const char **list, *model = drive->id->model;
 
-static int pdcnew_ide_dma_lostirq(ide_drive_t *drive)
-{
-       if (HWIF(drive)->resetproc != NULL)
-               HWIF(drive)->resetproc(drive);
-       return __ide_dma_lostirq(drive);
-}
-
-static int pdcnew_ide_dma_timeout(ide_drive_t *drive)
-{
-       if (HWIF(drive)->resetproc != NULL)
-               HWIF(drive)->resetproc(drive);
-       return __ide_dma_timeout(drive);
+       for (list = pdc_quirk_drives; *list != NULL; list++)
+               if (strstr(model, *list) != NULL)
+                       return 2;
+       return 0;
 }
 
 static void pdcnew_reset(ide_drive_t *drive)
@@ -599,8 +561,6 @@ static void __devinit init_hwif_pdc202new(ide_hwif_t *hwif)
        hwif->err_stops_fifo = 1;
 
        hwif->ide_dma_check = &pdcnew_config_drive_xfer_rate;
-       hwif->ide_dma_lostirq = &pdcnew_ide_dma_lostirq;
-       hwif->ide_dma_timeout = &pdcnew_ide_dma_timeout;
 
        if (!hwif->udma_four)
                hwif->udma_four = pdcnew_cable_detect(hwif) ? 0 : 1;
index 143239c..730e8d1 100644 (file)
@@ -123,26 +123,6 @@ static u8 pdc202xx_ratemask (ide_drive_t *drive)
        return mode;
 }
 
-static int check_in_drive_lists (ide_drive_t *drive, const char **list)
-{
-       struct hd_driveid *id = drive->id;
-
-       if (pdc_quirk_drives == list) {
-               while (*list) {
-                       if (strstr(id->model, *list++)) {
-                               return 2;
-                       }
-               }
-       } else {
-               while (*list) {
-                       if (!strcmp(*list++,id->model)) {
-                               return 1;
-                       }
-               }
-       }
-       return 0;
-}
-
 static int pdc202xx_tune_chipset (ide_drive_t *drive, u8 xferspeed)
 {
        ide_hwif_t *hwif        = HWIF(drive);
@@ -377,7 +357,12 @@ fast_ata_pio:
 
 static int pdc202xx_quirkproc (ide_drive_t *drive)
 {
-       return ((int) check_in_drive_lists(drive, pdc_quirk_drives));
+       const char **list, *model = drive->id->model;
+
+       for (list = pdc_quirk_drives; *list != NULL; list++)
+               if (strstr(model, *list) != NULL)
+                       return 2;
+       return 0;
 }
 
 static void pdc202xx_old_ide_dma_start(ide_drive_t *drive)
index edb37f3..52cfc2a 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/pci/piix.c       Version 0.45    May 12, 2006
+ *  linux/drivers/ide/pci/piix.c       Version 0.46    December 3, 2006
  *
  *  Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
  *  Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
@@ -163,7 +163,7 @@ static u8 piix_ratemask (ide_drive_t *drive)
         *      if the drive cannot see an 80pin cable.
         */
        if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
+               mode = min_t(u8, mode, 1);
        return mode;
 }
 
@@ -216,7 +216,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
-       int is_slave            = (&hwif->drives[1] == drive);
+       int is_slave            = drive->dn & 1;
        int master_port         = hwif->channel ? 0x42 : 0x40;
        int slave_port          = 0x44;
        unsigned long flags;
@@ -225,7 +225,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
        static DEFINE_SPINLOCK(tune_lock);
        int control = 0;
 
-                                /* ISP  RTC */
+                                    /* ISP  RTC */
        static const u8 timings[][2]= {
                                        { 0, 0 },
                                        { 0, 0 },
@@ -233,7 +233,7 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
                                        { 2, 1 },
                                        { 2, 3 }, };
 
-       pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
 
        /*
         * Master vs slave is synchronized above us but the slave register is
@@ -243,25 +243,24 @@ static void piix_tune_drive (ide_drive_t *drive, u8 pio)
        spin_lock_irqsave(&tune_lock, flags);
        pci_read_config_word(dev, master_port, &master_data);
 
-       if (pio >= 2)
+       if (pio > 1)
                control |= 1;   /* Programmable timing on */
        if (drive->media == ide_disk)
                control |= 4;   /* Prefetch, post write */
-       if (pio >= 3)
+       if (pio > 2)
                control |= 2;   /* IORDY */
        if (is_slave) {
-               master_data = master_data | 0x4000;
+               master_data |=  0x4000;
+               master_data &= ~0x0070;
                if (pio > 1) {
                        /* enable PPE, IE and TIME */
                        master_data = master_data | (control << 4);
-               } else {
-                       master_data &= ~0x0070;
                }
                pci_read_config_byte(dev, slave_port, &slave_data);
                slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
                slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
        } else {
-               master_data = master_data & 0xccf8;
+               master_data &= ~0x3307;
                if (pio > 1) {
                        /* enable PPE, IE and TIME */
                        master_data = master_data | control;
@@ -539,13 +538,19 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
        /*  0 */ DECLARE_PIIX_DEV("PIIXa"),
        /*  1 */ DECLARE_PIIX_DEV("PIIXb"),
 
-       {       /* 2 */
+       /*  2 */
+       {       /*
+                * MPIIX actually has only a single IDE channel mapped to
+                * the primary or secondary ports depending on the value
+                * of the bit 14 of the IDETIM register at offset 0x6c
+                */
                .name           = "MPIIX",
                .init_hwif      = init_hwif_piix,
                .channels       = 2,
                .autodma        = NODMA,
-               .enablebits     = {{0x6D,0x80,0x80}, {0x6F,0x80,0x80}},
+               .enablebits     = {{0x6d,0xc0,0x80}, {0x6d,0xc0,0xc0}},
                .bootable       = ON_BOARD,
+               .flags          = IDEPCI_FLAG_ISA_PORTS
        },
 
        /*  3 */ DECLARE_PIIX_DEV("PIIX3"),
index 90e79c0..2663ddb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/ide/pci/slc90e66.c   Version 0.12    May 12, 2006
+ *  linux/drivers/ide/pci/slc90e66.c   Version 0.13    December 30, 2006
  *
  *  Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org>
  *  Copyright (C) 2006 MontaVista Software, Inc. <source@mvista.com>
@@ -26,7 +26,7 @@ static u8 slc90e66_ratemask (ide_drive_t *drive)
        u8 mode = 2;
 
        if (!eighty_ninty_three(drive))
-               mode = min(mode, (u8)1);
+               mode = min_t(u8, mode, 1);
        return mode;
 }
 
@@ -65,36 +65,47 @@ static void slc90e66_tune_drive (ide_drive_t *drive, u8 pio)
 {
        ide_hwif_t *hwif        = HWIF(drive);
        struct pci_dev *dev     = hwif->pci_dev;
-       int is_slave            = (&hwif->drives[1] == drive);
+       int is_slave            = drive->dn & 1;
        int master_port         = hwif->channel ? 0x42 : 0x40;
        int slave_port          = 0x44;
        unsigned long flags;
        u16 master_data;
        u8 slave_data;
-                                /* ISP  RTC */
+       int control = 0;
+                                    /* ISP  RTC */
        static const u8 timings[][2]= {
-                                   { 0, 0 },
-                                   { 0, 0 },
-                                   { 1, 0 },
-                                   { 2, 1 },
-                                   { 2, 3 }, };
+                                       { 0, 0 },
+                                       { 0, 0 },
+                                       { 1, 0 },
+                                       { 2, 1 },
+                                       { 2, 3 }, };
 
-       pio = ide_get_best_pio_mode(drive, pio, 5, NULL);
+       pio = ide_get_best_pio_mode(drive, pio, 4, NULL);
        spin_lock_irqsave(&ide_lock, flags);
        pci_read_config_word(dev, master_port, &master_data);
+
+       if (pio > 1)
+               control |= 1;   /* Programmable timing on */
+       if (drive->media == ide_disk)
+               control |= 4;   /* Prefetch, post write */
+       if (pio > 2)
+               control |= 2;   /* IORDY */
        if (is_slave) {
-               master_data = master_data | 0x4000;
-               if (pio > 1)
+               master_data |=  0x4000;
+               master_data &= ~0x0070;
+               if (pio > 1) {
                        /* enable PPE, IE and TIME */
-                       master_data = master_data | 0x0070;
+                       master_data = master_data | (control << 4);
+               }
                pci_read_config_byte(dev, slave_port, &slave_data);
                slave_data = slave_data & (hwif->channel ? 0x0f : 0xf0);
                slave_data = slave_data | (((timings[pio][0] << 2) | timings[pio][1]) << (hwif->channel ? 4 : 0));
        } else {
-               master_data = master_data & 0xccf8;
-               if (pio > 1)
+               master_data &= ~0x3307;
+               if (pio > 1) {
                        /* enable PPE, IE and TIME */
-                       master_data = master_data | 0x0007;
+                       master_data = master_data | control;
+               }
                master_data = master_data | (timings[pio][0] << 12) | (timings[pio][1] << 8);
        }
        pci_write_config_word(dev, master_port, master_data);
@@ -173,7 +184,7 @@ static int slc90e66_config_drive_xfer_rate (ide_drive_t *drive)
 
        drive->init_speed = 0;
 
-       if (id && (id->capability & 1) && drive->autodma) {
+       if ((id->capability & 1) && drive->autodma) {
 
                if (ide_use_dma(drive) && slc90e66_config_drive_for_dma(drive))
                        return hwif->ide_dma_on(drive);
@@ -201,7 +212,7 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
                hwif->irq = hwif->channel ? 15 : 14;
 
        hwif->speedproc = &slc90e66_tune_chipset;
-       hwif->tuneproc = &slc90e66_tune_drive;
+       hwif->tuneproc  = &slc90e66_tune_drive;
 
        pci_read_config_byte(hwif->pci_dev, 0x47, &reg47);
 
@@ -213,14 +224,16 @@ static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
 
        hwif->atapi_dma = 1;
        hwif->ultra_mask = 0x1f;
-       hwif->mwdma_mask = 0x07;
-       hwif->swdma_mask = 0x07;
+       hwif->mwdma_mask = 0x06;
+       hwif->swdma_mask = 0x04;
 
-       if (!(hwif->udma_four))
+       if (!hwif->udma_four) {
                /* bit[0(1)]: 0:80, 1:40 */
                hwif->udma_four = (reg47 & mask) ? 0 : 1;
+       }
 
        hwif->ide_dma_check = &slc90e66_config_drive_xfer_rate;
+
        if (!noautodma)
                hwif->autodma = 1;
        hwif->drives[0].autodma = hwif->autodma;
diff --git a/drivers/ide/pci/tc86c001.c b/drivers/ide/pci/tc86c001.c
new file mode 100644 (file)
index 0000000..2ad72bb
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ * drivers/ide/pci/tc86c001.c  Version 1.00    Dec 12, 2006
+ *
+ * Copyright (C) 2002 Toshiba Corporation
+ * Copyright (C) 2005-2006 MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+static inline u8 tc86c001_ratemask(ide_drive_t *drive)
+{
+       return eighty_ninty_three(drive) ? 2 : 1;
+}
+
+static int tc86c001_tune_chipset(ide_drive_t *drive, u8 speed)
+{
+       ide_hwif_t *hwif        = HWIF(drive);
+       unsigned long scr_port  = hwif->config_data + (drive->dn ? 0x02 : 0x00);
+       u16 mode, scr           = hwif->INW(scr_port);
+
+       speed = ide_rate_filter(tc86c001_ratemask(drive), speed);
+
+       switch (speed) {
+               case XFER_UDMA_4:       mode = 0x00c0; break;
+               case XFER_UDMA_3:       mode = 0x00b0; break;
+               case XFER_UDMA_2:       mode = 0x00a0; break;
+               case XFER_UDMA_1:       mode = 0x0090; break;
+               case XFER_UDMA_0:       mode = 0x0080; break;
+               case XFER_MW_DMA_2:     mode = 0x0070; break;
+               case XFER_MW_DMA_1:     mode = 0x0060; break;
+               case XFER_MW_DMA_0:     mode = 0x0050; break;
+               case XFER_PIO_4:        mode = 0x0400; break;
+               case XFER_PIO_3:        mode = 0x0300; break;
+               case XFER_PIO_2:        mode = 0x0200; break;
+               case XFER_PIO_1:        mode = 0x0100; break;
+               case XFER_PIO_0:
+               default:                mode = 0x0000; break;
+       }
+
+       scr &= (speed < XFER_MW_DMA_0) ? 0xf8ff : 0xff0f;
+       scr |= mode;
+       hwif->OUTW(scr, scr_port);
+
+       return ide_config_drive_speed(drive, speed);
+}
+
+static void tc86c001_tune_drive(ide_drive_t *drive, u8 pio)
+{
+       pio =  ide_get_best_pio_mode(drive, pio, 4, NULL);
+       (void) tc86c001_tune_chipset(drive, XFER_PIO_0 + pio);
+}
+
+/*
+ * HACKITY HACK
+ *
+ * This is a workaround for the limitation 5 of the TC86C001 IDE controller:
+ * if a DMA transfer terminates prematurely, the controller leaves the device's
+ * interrupt request (INTRQ) pending and does not generate a PCI interrupt (or
+ * set the interrupt bit in the DMA status register), thus no PCI interrupt
+ * will occur until a DMA transfer has been successfully completed.
+ *
+ * We work around this by initiating dummy, zero-length DMA transfer on
+ * a DMA timeout expiration. I found no better way to do this with the current
+ * IDE core than to temporarily replace a higher level driver's timer expiry
+ * handler with our own backing up to that handler in case our recovery fails.
+ */
+static int tc86c001_timer_expiry(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif        = HWIF(drive);
+       ide_expiry_t *expiry    = ide_get_hwifdata(hwif);
+       ide_hwgroup_t *hwgroup  = HWGROUP(drive);
+       u8 dma_stat             = hwif->INB(hwif->dma_status);
+
+       /* Restore a higher level driver's expiry handler first. */
+       hwgroup->expiry = expiry;
+
+       if ((dma_stat & 5) == 1) {      /* DMA active and no interrupt */
+               unsigned long sc_base   = hwif->config_data;
+               unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
+               u8 dma_cmd              = hwif->INB(hwif->dma_command);
+
+               printk(KERN_WARNING "%s: DMA interrupt possibly stuck, "
+                      "attempting recovery...\n", drive->name);
+
+               /* Stop DMA */
+               hwif->OUTB(dma_cmd & ~0x01, hwif->dma_command);
+
+               /* Setup the dummy DMA transfer */
+               hwif->OUTW(0, sc_base + 0x0a);  /* Sector Count */
+               hwif->OUTW(0, twcr_port);       /* Transfer Word Count 1 or 2 */
+
+               /* Start the dummy DMA transfer */
+               hwif->OUTB(0x00, hwif->dma_command); /* clear R_OR_WCTR for write */
+               hwif->OUTB(0x01, hwif->dma_command); /* set START_STOPBM */
+
+               /*
+                * If an interrupt was pending, it should come thru shortly.
+                * If not, a higher level driver's expiry handler should
+                * eventually cause some kind of recovery from the DMA stall.
+                */
+               return WAIT_MIN_SLEEP;
+       }
+
+       /* Chain to the restored expiry handler if DMA wasn't active. */
+       if (likely(expiry != NULL))
+               return expiry(drive);
+
+       /* If there was no handler, "emulate" that for ide_timer_expiry()... */
+       return -1;
+}
+
+static void tc86c001_dma_start(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif        = HWIF(drive);
+       ide_hwgroup_t *hwgroup  = HWGROUP(drive);
+       unsigned long sc_base   = hwif->config_data;
+       unsigned long twcr_port = sc_base + (drive->dn ? 0x06 : 0x04);
+       unsigned long nsectors  = hwgroup->rq->nr_sectors;
+
+       /*
+        * We have to manually load the sector count and size into
+        * the appropriate system control registers for DMA to work
+        * with LBA48 and ATAPI devices...
+        */
+       hwif->OUTW(nsectors, sc_base + 0x0a);   /* Sector Count */
+       hwif->OUTW(SECTOR_SIZE / 2, twcr_port); /* Transfer Word Count 1/2 */
+
+       /* Install our timeout expiry hook, saving the current handler... */
+       ide_set_hwifdata(hwif, hwgroup->expiry);
+       hwgroup->expiry = &tc86c001_timer_expiry;
+
+       ide_dma_start(drive);
+}
+
+static int tc86c001_busproc(ide_drive_t *drive, int state)
+{
+       ide_hwif_t *hwif        = HWIF(drive);
+       unsigned long sc_base   = hwif->config_data;
+       u16 scr1;
+
+       /* System Control 1 Register bit 11 (ATA Hard Reset) read */
+       scr1 = hwif->INW(sc_base + 0x00);
+
+       switch (state) {
+               case BUSSTATE_ON:
+                       if (!(scr1 & 0x0800))
+                               return 0;
+                       scr1 &= ~0x0800;
+
+                       hwif->drives[0].failures = hwif->drives[1].failures = 0;
+                       break;
+               case BUSSTATE_OFF:
+                       if (scr1 & 0x0800)
+                               return 0;
+                       scr1 |= 0x0800;
+
+                       hwif->drives[0].failures = hwif->drives[0].max_failures + 1;
+                       hwif->drives[1].failures = hwif->drives[1].max_failures + 1;
+                       break;
+               default:
+                       return -EINVAL;
+       }
+
+       /* System Control 1 Register bit 11 (ATA Hard Reset) write */
+       hwif->OUTW(scr1, sc_base + 0x00);
+       return 0;
+}
+
+static int config_chipset_for_dma(ide_drive_t *drive)
+{
+       u8 speed = ide_dma_speed(drive, tc86c001_ratemask(drive));
+
+       if (!speed)
+               return 0;
+
+       (void) tc86c001_tune_chipset(drive, speed);
+       return ide_dma_enable(drive);
+}
+
+static int tc86c001_config_drive_xfer_rate(ide_drive_t *drive)
+{
+       ide_hwif_t *hwif        = HWIF(drive);
+       struct hd_driveid *id   = drive->id;
+
+       if ((id->capability & 1) && drive->autodma) {
+
+               if (ide_use_dma(drive) && config_chipset_for_dma(drive))
+                       return hwif->ide_dma_on(drive);
+
+               goto fast_ata_pio;
+
+       } else if ((id->capability & 8) || (id->field_valid & 2)) {
+fast_ata_pio:
+               tc86c001_tune_drive(drive, 255);
+               return hwif->ide_dma_off_quietly(drive);
+       }
+       /* IORDY not supported */
+       return 0;
+}
+
+static void __devinit init_hwif_tc86c001(ide_hwif_t *hwif)
+{
+       unsigned long sc_base   = pci_resource_start(hwif->pci_dev, 5);
+       u16 scr1                = hwif->INW(sc_base + 0x00);;
+
+       /* System Control 1 Register bit 15 (Soft Reset) set */
+       hwif->OUTW(scr1 |  0x8000, sc_base + 0x00);
+
+       /* System Control 1 Register bit 14 (FIFO Reset) set */
+       hwif->OUTW(scr1 |  0x4000, sc_base + 0x00);
+
+       /* System Control 1 Register: reset clear */
+       hwif->OUTW(scr1 & ~0xc000, sc_base + 0x00);
+
+       /* Store the system control register base for convenience... */
+       hwif->config_data = sc_base;
+
+       hwif->tuneproc  = &tc86c001_tune_drive;
+       hwif->speedproc = &tc86c001_tune_chipset;
+       hwif->busproc   = &tc86c001_busproc;
+
+       hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
+
+       if (!hwif->dma_base)
+               return;
+
+       /*
+        * Sector Count Control Register bits 0 and 1 set:
+        * software sets Sector Count Register for master and slave device
+        */
+       hwif->OUTW(0x0003, sc_base + 0x0c);
+
+       /* Sector Count Register limit */
+       hwif->rqsize     = 0xffff;
+
+       hwif->atapi_dma  = 1;
+       hwif->ultra_mask = 0x1f;
+       hwif->mwdma_mask = 0x07;
+
+       hwif->ide_dma_check     = &tc86c001_config_drive_xfer_rate;
+       hwif->dma_start         = &tc86c001_dma_start;
+
+       if (!hwif->udma_four) {
+               /*
+                * System Control  1 Register bit 13 (PDIAGN):
+                * 0=80-pin cable, 1=40-pin cable
+                */
+               scr1 = hwif->INW(sc_base + 0x00);
+               hwif->udma_four = (scr1 & 0x2000) ? 0 : 1;
+       }
+
+       if (!noautodma)
+               hwif->autodma = 1;
+       hwif->drives[0].autodma = hwif->drives[1].autodma = hwif->autodma;
+}
+
+static unsigned int __devinit init_chipset_tc86c001(struct pci_dev *dev,
+                                                       const char *name)
+{
+       int err = pci_request_region(dev, 5, name);
+
+       if (err)
+               printk(KERN_ERR "%s: system control regs already in use", name);
+       return err;
+}
+
+static ide_pci_device_t tc86c001_chipset __devinitdata = {
+       .name           = "TC86C001",
+       .init_chipset   = init_chipset_tc86c001,
+       .init_hwif      = init_hwif_tc86c001,
+       .channels       = 1,
+       .autodma        = AUTODMA,
+       .bootable       = OFF_BOARD
+};
+
+static int __devinit tc86c001_init_one(struct pci_dev *dev,
+                                      const struct pci_device_id *id)
+{
+       return ide_setup_pci_device(dev, &tc86c001_chipset);
+}
+
+static struct pci_device_id tc86c001_pci_tbl[] = {
+       { PCI_VENDOR_ID_TOSHIBA_2, PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
+         PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, tc86c001_pci_tbl);
+
+static struct pci_driver driver = {
+       .name           = "TC86C001",
+       .id_table       = tc86c001_pci_tbl,
+       .probe          = tc86c001_init_one
+};
+
+static int __init tc86c001_ide_init(void)
+{
+       return ide_pci_register_driver(&driver);
+}
+module_init(tc86c001_ide_init);
+
+MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
+MODULE_DESCRIPTION("PCI driver module for TC86C001 IDE");
+MODULE_LICENSE("GPL");
index 695e239..a52c80f 100644 (file)
@@ -783,10 +783,11 @@ static LIST_HEAD(ide_pci_drivers);
  *     Returns are the same as for pci_register_driver
  */
 
-int __ide_pci_register_driver(struct pci_driver *driver, struct module *module)
+int __ide_pci_register_driver(struct pci_driver *driver, struct module *module,
+                             const char *mod_name)
 {
        if(!pre_init)
-               return __pci_register_driver(driver, module);
+               return __pci_register_driver(driver, module, mod_name);
        driver->driver.owner = module;
        list_add_tail(&driver->node, &ide_pci_drivers);
        return 0;
@@ -862,6 +863,6 @@ void __init ide_scan_pcibus (int scan_direction)
        {
                list_del(l);
                d = list_entry(l, struct pci_driver, node);
-               __pci_register_driver(d, d->driver.owner);
+               __pci_register_driver(d, d->driver.owner, d->driver.mod_name);
        }
 }
index af93979..d2bb5a9 100644 (file)
@@ -360,8 +360,7 @@ static int netevent_callback(struct notifier_block *self, unsigned long event,
        if (event == NETEVENT_NEIGH_UPDATE) {
                struct neighbour *neigh = ctx;
 
-               if (neigh->dev->type == ARPHRD_INFINIBAND &&
-                   (neigh->nud_state & NUD_VALID)) {
+               if (neigh->nud_state & NUD_VALID) {
                        set_timeout(jiffies);
                }
        }
index 5ed141e..13efd41 100644 (file)
@@ -642,7 +642,8 @@ static void snoop_recv(struct ib_mad_qp_info *qp_info,
        spin_unlock_irqrestore(&qp_info->snoop_lock, flags);
 }
 
-static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
+static void build_smp_wc(struct ib_qp *qp,
+                        u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
                         struct ib_wc *wc)
 {
        memset(wc, 0, sizeof *wc);
@@ -652,7 +653,7 @@ static void build_smp_wc(u64 wr_id, u16 slid, u16 pkey_index, u8 port_num,
        wc->pkey_index = pkey_index;
        wc->byte_len = sizeof(struct ib_mad) + sizeof(struct ib_grh);
        wc->src_qp = IB_QP0;
-       wc->qp_num = IB_QP0;
+       wc->qp = qp;
        wc->slid = slid;
        wc->sl = 0;
        wc->dlid_path_bits = 0;
@@ -713,7 +714,8 @@ static int handle_outgoing_dr_smp(struct ib_mad_agent_private *mad_agent_priv,
                goto out;
        }
 
-       build_smp_wc(send_wr->wr_id, be16_to_cpu(smp->dr_slid),
+       build_smp_wc(mad_agent_priv->agent.qp,
+                    send_wr->wr_id, be16_to_cpu(smp->dr_slid),
                     send_wr->wr.ud.pkey_index,
                     send_wr->wr.ud.port_num, &mad_wc);
 
@@ -2355,7 +2357,8 @@ static void local_completions(struct work_struct *work)
                         * Defined behavior is to complete response
                         * before request
                         */
-                       build_smp_wc((unsigned long) local->mad_send_wr,
+                       build_smp_wc(recv_mad_agent->agent.qp,
+                                    (unsigned long) local->mad_send_wr,
                                     be16_to_cpu(IB_LID_PERMISSIVE),
                                     0, recv_mad_agent->agent.port_num, &wc);
 
index 743247e..df1efbc 100644 (file)
@@ -933,7 +933,7 @@ ssize_t ib_uverbs_poll_cq(struct ib_uverbs_file *file,
                resp->wc[i].vendor_err     = wc[i].vendor_err;
                resp->wc[i].byte_len       = wc[i].byte_len;
                resp->wc[i].imm_data       = (__u32 __force) wc[i].imm_data;
-               resp->wc[i].qp_num         = wc[i].qp_num;
+               resp->wc[i].qp_num         = wc[i].qp->qp_num;
                resp->wc[i].src_qp         = wc[i].src_qp;
                resp->wc[i].wc_flags       = wc[i].wc_flags;
                resp->wc[i].pkey_index     = wc[i].pkey_index;
index 05c9154..5175c99 100644 (file)
@@ -153,7 +153,7 @@ static inline int c2_poll_one(struct c2_dev *c2dev,
 
        entry->status = c2_cqe_status_to_openib(c2_wr_get_result(ce));
        entry->wr_id = ce->hdr.context;
-       entry->qp_num = ce->handle;
+       entry->qp = &qp->ibqp;
        entry->wc_flags = 0;
        entry->slid = 0;
        entry->sl = 0;
index 1c72203..cf95ee4 100644 (file)
@@ -119,13 +119,14 @@ struct ehca_qp {
        struct ipz_qp_handle ipz_qp_handle;
        struct ehca_pfqp pf;
        struct ib_qp_init_attr init_attr;
-       u64 uspace_squeue;
-       u64 uspace_rqueue;
-       u64 uspace_fwh;
        struct ehca_cq *send_cq;
        struct ehca_cq *recv_cq;
        unsigned int sqerr_purgeflag;
        struct hlist_node list_entries;
+       /* mmap counter for resources mapped into user space */
+       u32 mm_count_squeue;
+       u32 mm_count_rqueue;
+       u32 mm_count_galpa;
 };
 
 /* must be power of 2 */
@@ -142,13 +143,14 @@ struct ehca_cq {
        struct ipz_cq_handle ipz_cq_handle;
        struct ehca_pfcq pf;
        spinlock_t cb_lock;
-       u64 uspace_queue;
-       u64 uspace_fwh;
        struct hlist_head qp_hashtab[QP_HASHTAB_LEN];
        struct list_head entry;
        u32 nr_callbacks;
        spinlock_t task_lock;
        u32 ownpid;
+       /* mmap counter for resources mapped into user space */
+       u32 mm_count_queue;
+       u32 mm_count_galpa;
 };
 
 enum ehca_mr_flag {
@@ -248,20 +250,6 @@ struct ehca_ucontext {
        struct ib_ucontext ib_ucontext;
 };
 
-struct ehca_module *ehca_module_new(void);
-
-int ehca_module_delete(struct ehca_module *me);
-
-int ehca_eq_ctor(struct ehca_eq *eq);
-
-int ehca_eq_dtor(struct ehca_eq *eq);
-
-struct ehca_shca *ehca_shca_new(void);
-
-int ehca_shca_delete(struct ehca_shca *me);
-
-struct ehca_sport *ehca_sport_new(struct ehca_shca *anchor);
-
 int ehca_init_pd_cache(void);
 void ehca_cleanup_pd_cache(void);
 int ehca_init_cq_cache(void);
@@ -283,7 +271,6 @@ extern int ehca_port_act_time;
 extern int ehca_use_hp_mr;
 
 struct ipzu_queue_resp {
-       u64 queue;        /* points to first queue entry */
        u32 qe_size;      /* queue entry size */
        u32 act_nr_of_sg;
        u32 queue_length; /* queue length allocated in bytes */
@@ -296,7 +283,6 @@ struct ehca_create_cq_resp {
        u32 cq_number;
        u32 token;
        struct ipzu_queue_resp ipz_queue;
-       struct h_galpas galpas;
 };
 
 struct ehca_create_qp_resp {
@@ -309,7 +295,6 @@ struct ehca_create_qp_resp {
        u32 dummy; /* padding for 8 byte alignment */
        struct ipzu_queue_resp ipz_squeue;
        struct ipzu_queue_resp ipz_rqueue;
-       struct h_galpas galpas;
 };
 
 struct ehca_alloc_cq_parms {
index 6074c89..9291a86 100644 (file)
@@ -267,7 +267,6 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
        if (context) {
                struct ipz_queue *ipz_queue = &my_cq->ipz_queue;
                struct ehca_create_cq_resp resp;
-               struct vm_area_struct *vma;
                memset(&resp, 0, sizeof(resp));
                resp.cq_number = my_cq->cq_number;
                resp.token = my_cq->token;
@@ -276,40 +275,14 @@ struct ib_cq *ehca_create_cq(struct ib_device *device, int cqe,
                resp.ipz_queue.queue_length = ipz_queue->queue_length;
                resp.ipz_queue.pagesize = ipz_queue->pagesize;
                resp.ipz_queue.toggle_state = ipz_queue->toggle_state;
-               ret = ehca_mmap_nopage(((u64)(my_cq->token) << 32) | 0x12000000,
-                                      ipz_queue->queue_length,
-                                      (void**)&resp.ipz_queue.queue,
-                                      &vma);
-               if (ret) {
-                       ehca_err(device, "Could not mmap queue pages");
-                       cq = ERR_PTR(ret);
-                       goto create_cq_exit4;
-               }
-               my_cq->uspace_queue = resp.ipz_queue.queue;
-               resp.galpas = my_cq->galpas;
-               ret = ehca_mmap_register(my_cq->galpas.user.fw_handle,
-                                        (void**)&resp.galpas.kernel.fw_handle,
-                                        &vma);
-               if (ret) {
-                       ehca_err(device, "Could not mmap fw_handle");
-                       cq = ERR_PTR(ret);
-                       goto create_cq_exit5;
-               }
-               my_cq->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
                if (ib_copy_to_udata(udata, &resp, sizeof(resp))) {
                        ehca_err(device, "Copy to udata failed.");
-                       goto create_cq_exit6;
+                       goto create_cq_exit4;
                }
        }
 
        return cq;
 
-create_cq_exit6:
-       ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
-
-create_cq_exit5:
-       ehca_munmap(my_cq->uspace_queue, my_cq->ipz_queue.queue_length);
-
 create_cq_exit4:
        ipz_queue_dtor(&my_cq->ipz_queue);
 
@@ -333,7 +306,6 @@ create_cq_exit1:
 int ehca_destroy_cq(struct ib_cq *cq)
 {
        u64 h_ret;
-       int ret;
        struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
        int cq_num = my_cq->cq_number;
        struct ib_device *device = cq->device;
@@ -343,6 +315,20 @@ int ehca_destroy_cq(struct ib_cq *cq)
        u32 cur_pid = current->tgid;
        unsigned long flags;
 
+       if (cq->uobject) {
+               if (my_cq->mm_count_galpa || my_cq->mm_count_queue) {
+                       ehca_err(device, "Resources still referenced in "
+                                "user space cq_num=%x", my_cq->cq_number);
+                       return -EINVAL;
+               }
+               if (my_cq->ownpid != cur_pid) {
+                       ehca_err(device, "Invalid caller pid=%x ownpid=%x "
+                                "cq_num=%x",
+                                cur_pid, my_cq->ownpid, my_cq->cq_number);
+                       return -EINVAL;
+               }
+       }
+
        spin_lock_irqsave(&ehca_cq_idr_lock, flags);
        while (my_cq->nr_callbacks) {
                spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
@@ -353,25 +339,6 @@ int ehca_destroy_cq(struct ib_cq *cq)
        idr_remove(&ehca_cq_idr, my_cq->token);
        spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
 
-       if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
-               ehca_err(device, "Invalid caller pid=%x ownpid=%x",
-                        cur_pid, my_cq->ownpid);
-               return -EINVAL;
-       }
-
-       /* un-mmap if vma alloc */
-       if (my_cq->uspace_queue ) {
-               ret = ehca_munmap(my_cq->uspace_queue,
-                                 my_cq->ipz_queue.queue_length);
-               if (ret)
-                       ehca_err(device, "Could not munmap queue ehca_cq=%p "
-                                "cq_num=%x", my_cq, cq_num);
-               ret = ehca_munmap(my_cq->uspace_fwh, EHCA_PAGESIZE);
-               if (ret)
-                       ehca_err(device, "Could not munmap fwh ehca_cq=%p "
-                                "cq_num=%x", my_cq, cq_num);
-       }
-
        h_ret = hipz_h_destroy_cq(adapter_handle, my_cq, 0);
        if (h_ret == H_R_STATE) {
                /* cq in err: read err data and destroy it forcibly */
@@ -400,7 +367,7 @@ int ehca_resize_cq(struct ib_cq *cq, int cqe, struct ib_udata *udata)
        struct ehca_cq *my_cq = container_of(cq, struct ehca_cq, ib_cq);
        u32 cur_pid = current->tgid;
 
-       if (my_cq->uspace_queue && my_cq->ownpid != cur_pid) {
+       if (cq->uobject && my_cq->ownpid != cur_pid) {
                ehca_err(cq->device, "Invalid caller pid=%x ownpid=%x",
                         cur_pid, my_cq->ownpid);
                return -EINVAL;
index cd7789f..95fd59f 100644 (file)
@@ -171,14 +171,6 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma);
 
 void ehca_poll_eqs(unsigned long data);
 
-int ehca_mmap_nopage(u64 foffset,u64 length,void **mapped,
-                    struct vm_area_struct **vma);
-
-int ehca_mmap_register(u64 physical,void **mapped,
-                      struct vm_area_struct **vma);
-
-int ehca_munmap(unsigned long addr, size_t len);
-
 #ifdef CONFIG_PPC_64K_PAGES
 void *ehca_alloc_fw_ctrlblock(gfp_t flags);
 void ehca_free_fw_ctrlblock(void *ptr);
index 6574fbb..1155bcf 100644 (file)
@@ -52,7 +52,7 @@
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_AUTHOR("Christoph Raisch <raisch@de.ibm.com>");
 MODULE_DESCRIPTION("IBM eServer HCA InfiniBand Device Driver");
-MODULE_VERSION("SVNEHCA_0019");
+MODULE_VERSION("SVNEHCA_0020");
 
 int ehca_open_aqp1     = 0;
 int ehca_debug_level   = 0;
@@ -288,7 +288,7 @@ int ehca_init_device(struct ehca_shca *shca)
        strlcpy(shca->ib_device.name, "ehca%d", IB_DEVICE_NAME_MAX);
        shca->ib_device.owner               = THIS_MODULE;
 
-       shca->ib_device.uverbs_abi_ver      = 5;
+       shca->ib_device.uverbs_abi_ver      = 6;
        shca->ib_device.uverbs_cmd_mask     =
                (1ull << IB_USER_VERBS_CMD_GET_CONTEXT)         |
                (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE)        |
@@ -790,7 +790,7 @@ int __init ehca_module_init(void)
        int ret;
 
        printk(KERN_INFO "eHCA Infiniband Device Driver "
-                        "(Rel.: SVNEHCA_0019)\n");
+                        "(Rel.: SVNEHCA_0020)\n");
        idr_init(&ehca_qp_idr);
        idr_init(&ehca_cq_idr);
        spin_lock_init(&ehca_qp_idr_lock);
index 34b8555..95efef9 100644 (file)
@@ -637,7 +637,6 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
                struct ipz_queue *ipz_rqueue = &my_qp->ipz_rqueue;
                struct ipz_queue *ipz_squeue = &my_qp->ipz_squeue;
                struct ehca_create_qp_resp resp;
-               struct vm_area_struct * vma;
                memset(&resp, 0, sizeof(resp));
 
                resp.qp_num = my_qp->real_qp_num;
@@ -651,59 +650,21 @@ struct ib_qp *ehca_create_qp(struct ib_pd *pd,
                resp.ipz_rqueue.queue_length = ipz_rqueue->queue_length;
                resp.ipz_rqueue.pagesize = ipz_rqueue->pagesize;
                resp.ipz_rqueue.toggle_state = ipz_rqueue->toggle_state;
-               ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x22000000,
-                                      ipz_rqueue->queue_length,
-                                      (void**)&resp.ipz_rqueue.queue,
-                                      &vma);
-               if (ret) {
-                       ehca_err(pd->device, "Could not mmap rqueue pages");
-                       goto create_qp_exit3;
-               }
-               my_qp->uspace_rqueue = resp.ipz_rqueue.queue;
                /* squeue properties */
                resp.ipz_squeue.qe_size = ipz_squeue->qe_size;
                resp.ipz_squeue.act_nr_of_sg = ipz_squeue->act_nr_of_sg;
                resp.ipz_squeue.queue_length = ipz_squeue->queue_length;
                resp.ipz_squeue.pagesize = ipz_squeue->pagesize;
                resp.ipz_squeue.toggle_state = ipz_squeue->toggle_state;
-               ret = ehca_mmap_nopage(((u64)(my_qp->token) << 32) | 0x23000000,
-                                      ipz_squeue->queue_length,
-                                      (void**)&resp.ipz_squeue.queue,
-                                      &vma);
-               if (ret) {
-                       ehca_err(pd->device, "Could not mmap squeue pages");
-                       goto create_qp_exit4;
-               }
-               my_qp->uspace_squeue = resp.ipz_squeue.queue;
-               /* fw_handle */
-               resp.galpas = my_qp->galpas;
-               ret = ehca_mmap_register(my_qp->galpas.user.fw_handle,
-                                        (void**)&resp.galpas.kernel.fw_handle,
-                                        &vma);
-               if (ret) {
-                       ehca_err(pd->device, "Could not mmap fw_handle");
-                       goto create_qp_exit5;
-               }
-               my_qp->uspace_fwh = (u64)resp.galpas.kernel.fw_handle;
-
                if (ib_copy_to_udata(udata, &resp, sizeof resp)) {
                        ehca_err(pd->device, "Copy to udata failed");
                        ret = -EINVAL;
-                       goto create_qp_exit6;
+                       goto create_qp_exit3;
                }
        }
 
        return &my_qp->ib_qp;
 
-create_qp_exit6:
-       ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
-
-create_qp_exit5:
-       ehca_munmap(my_qp->uspace_squeue, my_qp->ipz_squeue.queue_length);
-
-create_qp_exit4:
-       ehca_munmap(my_qp->uspace_rqueue, my_qp->ipz_rqueue.queue_length);
-
 create_qp_exit3:
        ipz_queue_dtor(&my_qp->ipz_rqueue);
        ipz_queue_dtor(&my_qp->ipz_squeue);
@@ -931,7 +892,7 @@ static int internal_modify_qp(struct ib_qp *ibqp,
             my_qp->qp_type == IB_QPT_SMI) &&
            statetrans == IB_QPST_SQE2RTS) {
                /* mark next free wqe if kernel */
-               if (my_qp->uspace_squeue == 0) {
+               if (!ibqp->uobject) {
                        struct ehca_wqe *wqe;
                        /* lock send queue */
                        spin_lock_irqsave(&my_qp->spinlock_s, spl_flags);
@@ -1417,11 +1378,18 @@ int ehca_destroy_qp(struct ib_qp *ibqp)
        enum ib_qp_type qp_type;
        unsigned long flags;
 
-       if (my_pd->ib_pd.uobject && my_pd->ib_pd.uobject->context &&
-           my_pd->ownpid != cur_pid) {
-               ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x",
-                        cur_pid, my_pd->ownpid);
-               return -EINVAL;
+       if (ibqp->uobject) {
+               if (my_qp->mm_count_galpa ||
+                   my_qp->mm_count_rqueue || my_qp->mm_count_squeue) {
+                       ehca_err(ibqp->device, "Resources still referenced in "
+                                "user space qp_num=%x", ibqp->qp_num);
+                       return -EINVAL;
+               }
+               if (my_pd->ownpid != cur_pid) {
+                       ehca_err(ibqp->device, "Invalid caller pid=%x ownpid=%x",
+                                cur_pid, my_pd->ownpid);
+                       return -EINVAL;
+               }
        }
 
        if (my_qp->send_cq) {
@@ -1439,24 +1407,6 @@ int ehca_destroy_qp(struct ib_qp *ibqp)
        idr_remove(&ehca_qp_idr, my_qp->token);
        spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
 
-       /* un-mmap if vma alloc */
-       if (my_qp->uspace_rqueue) {
-               ret = ehca_munmap(my_qp->uspace_rqueue,
-                                 my_qp->ipz_rqueue.queue_length);
-               if (ret)
-                       ehca_err(ibqp->device, "Could not munmap rqueue "
-                                "qp_num=%x", qp_num);
-               ret = ehca_munmap(my_qp->uspace_squeue,
-                                 my_qp->ipz_squeue.queue_length);
-               if (ret)
-                       ehca_err(ibqp->device, "Could not munmap squeue "
-                                "qp_num=%x", qp_num);
-               ret = ehca_munmap(my_qp->uspace_fwh, EHCA_PAGESIZE);
-               if (ret)
-                       ehca_err(ibqp->device, "Could not munmap fwh qp_num=%x",
-                                qp_num);
-       }
-
        h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
        if (h_ret != H_SUCCESS) {
                ehca_err(ibqp->device, "hipz_h_destroy_qp() failed rc=%lx "
index b46bda1..08d3f89 100644 (file)
@@ -579,7 +579,7 @@ poll_cq_one_read_cqe:
        } else
                wc->status = IB_WC_SUCCESS;
 
-       wc->qp_num = cqe->local_qp_number;
+       wc->qp = NULL;
        wc->byte_len = cqe->nr_bytes_transferred;
        wc->pkey_index = cqe->pkey_index;
        wc->slid = cqe->rlid;
index e08764e..73db920 100644 (file)
@@ -68,105 +68,183 @@ int ehca_dealloc_ucontext(struct ib_ucontext *context)
        return 0;
 }
 
-struct page *ehca_nopage(struct vm_area_struct *vma,
-                        unsigned long address, int *type)
+static void ehca_mm_open(struct vm_area_struct *vma)
 {
-       struct page *mypage = NULL;
-       u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
-       u32 idr_handle = fileoffset >> 32;
-       u32 q_type = (fileoffset >> 28) & 0xF;    /* CQ, QP,...        */
-       u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
-       u32 cur_pid = current->tgid;
-       unsigned long flags;
-       struct ehca_cq *cq;
-       struct ehca_qp *qp;
-       struct ehca_pd *pd;
-       u64 offset;
-       void *vaddr;
+       u32 *count = (u32*)vma->vm_private_data;
+       if (!count) {
+               ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
+                            vma->vm_start, vma->vm_end);
+               return;
+       }
+       (*count)++;
+       if (!(*count))
+               ehca_gen_err("Use count overflow vm_start=%lx vm_end=%lx",
+                            vma->vm_start, vma->vm_end);
+       ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
+                    vma->vm_start, vma->vm_end, *count);
+}
 
-       switch (q_type) {
-       case 1: /* CQ */
-               spin_lock_irqsave(&ehca_cq_idr_lock, flags);
-               cq = idr_find(&ehca_cq_idr, idr_handle);
-               spin_unlock_irqrestore(&ehca_cq_idr_lock, flags);
+static void ehca_mm_close(struct vm_area_struct *vma)
+{
+       u32 *count = (u32*)vma->vm_private_data;
+       if (!count) {
+               ehca_gen_err("Invalid vma struct vm_start=%lx vm_end=%lx",
+                            vma->vm_start, vma->vm_end);
+               return;
+       }
+       (*count)--;
+       ehca_gen_dbg("vm_start=%lx vm_end=%lx count=%x",
+                    vma->vm_start, vma->vm_end, *count);
+}
 
-               /* make sure this mmap really belongs to the authorized user */
-               if (!cq) {
-                       ehca_gen_err("cq is NULL ret=NOPAGE_SIGBUS");
-                       return NOPAGE_SIGBUS;
+static struct vm_operations_struct vm_ops = {
+       .open = ehca_mm_open,
+       .close = ehca_mm_close,
+};
+
+static int ehca_mmap_fw(struct vm_area_struct *vma, struct h_galpas *galpas,
+                       u32 *mm_count)
+{
+       int ret;
+       u64 vsize, physical;
+
+       vsize = vma->vm_end - vma->vm_start;
+       if (vsize != EHCA_PAGESIZE) {
+               ehca_gen_err("invalid vsize=%lx", vma->vm_end - vma->vm_start);
+               return -EINVAL;
+       }
+
+       physical = galpas->user.fw_handle;
+       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+       ehca_gen_dbg("vsize=%lx physical=%lx", vsize, physical);
+       /* VM_IO | VM_RESERVED are set by remap_pfn_range() */
+       ret = remap_pfn_range(vma, vma->vm_start, physical >> PAGE_SHIFT,
+                             vsize, vma->vm_page_prot);
+       if (unlikely(ret)) {
+               ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
+               return -ENOMEM;
+       }
+
+       vma->vm_private_data = mm_count;
+       (*mm_count)++;
+       vma->vm_ops = &vm_ops;
+
+       return 0;
+}
+
+static int ehca_mmap_queue(struct vm_area_struct *vma, struct ipz_queue *queue,
+                          u32 *mm_count)
+{
+       int ret;
+       u64 start, ofs;
+       struct page *page;
+
+       vma->vm_flags |= VM_RESERVED;
+       start = vma->vm_start;
+       for (ofs = 0; ofs < queue->queue_length; ofs += PAGE_SIZE) {
+               u64 virt_addr = (u64)ipz_qeit_calc(queue, ofs);
+               page = virt_to_page(virt_addr);
+               ret = vm_insert_page(vma, start, page);
+               if (unlikely(ret)) {
+                       ehca_gen_err("vm_insert_page() failed rc=%x", ret);
+                       return ret;
                }
+               start +=  PAGE_SIZE;
+       }
+       vma->vm_private_data = mm_count;
+       (*mm_count)++;
+       vma->vm_ops = &vm_ops;
 
-               if (cq->ownpid != cur_pid) {
+       return 0;
+}
+
+static int ehca_mmap_cq(struct vm_area_struct *vma, struct ehca_cq *cq,
+                       u32 rsrc_type)
+{
+       int ret;
+
+       switch (rsrc_type) {
+       case 1: /* galpa fw handle */
+               ehca_dbg(cq->ib_cq.device, "cq_num=%x fw", cq->cq_number);
+               ret = ehca_mmap_fw(vma, &cq->galpas, &cq->mm_count_galpa);
+               if (unlikely(ret)) {
                        ehca_err(cq->ib_cq.device,
-                                "Invalid caller pid=%x ownpid=%x",
-                                cur_pid, cq->ownpid);
-                       return NOPAGE_SIGBUS;
+                                "ehca_mmap_fw() failed rc=%x cq_num=%x",
+                                ret, cq->cq_number);
+                       return ret;
                }
+               break;
 
-               if (rsrc_type == 2) {
-                       ehca_dbg(cq->ib_cq.device, "cq=%p cq queuearea", cq);
-                       offset = address - vma->vm_start;
-                       vaddr = ipz_qeit_calc(&cq->ipz_queue, offset);
-                       ehca_dbg(cq->ib_cq.device, "offset=%lx vaddr=%p",
-                                offset, vaddr);
-                       mypage = virt_to_page(vaddr);
+       case 2: /* cq queue_addr */
+               ehca_dbg(cq->ib_cq.device, "cq_num=%x queue", cq->cq_number);
+               ret = ehca_mmap_queue(vma, &cq->ipz_queue, &cq->mm_count_queue);
+               if (unlikely(ret)) {
+                       ehca_err(cq->ib_cq.device,
+                                "ehca_mmap_queue() failed rc=%x cq_num=%x",
+                                ret, cq->cq_number);
+                       return ret;
                }
                break;
 
-       case 2: /* QP */
-               spin_lock_irqsave(&ehca_qp_idr_lock, flags);
-               qp = idr_find(&ehca_qp_idr, idr_handle);
-               spin_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+       default:
+               ehca_err(cq->ib_cq.device, "bad resource type=%x cq_num=%x",
+                        rsrc_type, cq->cq_number);
+               return -EINVAL;
+       }
 
-               /* make sure this mmap really belongs to the authorized user */
-               if (!qp) {
-                       ehca_gen_err("qp is NULL ret=NOPAGE_SIGBUS");
-                       return NOPAGE_SIGBUS;
+       return 0;
+}
+
+static int ehca_mmap_qp(struct vm_area_struct *vma, struct ehca_qp *qp,
+                       u32 rsrc_type)
+{
+       int ret;
+
+       switch (rsrc_type) {
+       case 1: /* galpa fw handle */
+               ehca_dbg(qp->ib_qp.device, "qp_num=%x fw", qp->ib_qp.qp_num);
+               ret = ehca_mmap_fw(vma, &qp->galpas, &qp->mm_count_galpa);
+               if (unlikely(ret)) {
+                       ehca_err(qp->ib_qp.device,
+                                "remap_pfn_range() failed ret=%x qp_num=%x",
+                                ret, qp->ib_qp.qp_num);
+                       return -ENOMEM;
                }
+               break;
 
-               pd = container_of(qp->ib_qp.pd, struct ehca_pd, ib_pd);
-               if (pd->ownpid != cur_pid) {
+       case 2: /* qp rqueue_addr */
+               ehca_dbg(qp->ib_qp.device, "qp_num=%x rqueue",
+                        qp->ib_qp.qp_num);
+               ret = ehca_mmap_queue(vma, &qp->ipz_rqueue, &qp->mm_count_rqueue);
+               if (unlikely(ret)) {
                        ehca_err(qp->ib_qp.device,
-                                "Invalid caller pid=%x ownpid=%x",
-                                cur_pid, pd->ownpid);
-                       return NOPAGE_SIGBUS;
+                                "ehca_mmap_queue(rq) failed rc=%x qp_num=%x",
+                                ret, qp->ib_qp.qp_num);
+                       return ret;
                }
+               break;
 
-               if (rsrc_type == 2) {   /* rqueue */
-                       ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueuearea", qp);
-                       offset = address - vma->vm_start;
-                       vaddr = ipz_qeit_calc(&qp->ipz_rqueue, offset);
-                       ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
-                                offset, vaddr);
-                       mypage = virt_to_page(vaddr);
-               } else if (rsrc_type == 3) {    /* squeue */
-                       ehca_dbg(qp->ib_qp.device, "qp=%p qp squeuearea", qp);
-                       offset = address - vma->vm_start;
-                       vaddr = ipz_qeit_calc(&qp->ipz_squeue, offset);
-                       ehca_dbg(qp->ib_qp.device, "offset=%lx vaddr=%p",
-                                offset, vaddr);
-                       mypage = virt_to_page(vaddr);
+       case 3: /* qp squeue_addr */
+               ehca_dbg(qp->ib_qp.device, "qp_num=%x squeue",
+                        qp->ib_qp.qp_num);
+               ret = ehca_mmap_queue(vma, &qp->ipz_squeue, &qp->mm_count_squeue);
+               if (unlikely(ret)) {
+                       ehca_err(qp->ib_qp.device,
+                                "ehca_mmap_queue(sq) failed rc=%x qp_num=%x",
+                                ret, qp->ib_qp.qp_num);
+                       return ret;
                }
                break;
 
        default:
-               ehca_gen_err("bad queue type %x", q_type);
-               return NOPAGE_SIGBUS;
-       }
-
-       if (!mypage) {
-               ehca_gen_err("Invalid page adr==NULL ret=NOPAGE_SIGBUS");
-               return NOPAGE_SIGBUS;
+               ehca_err(qp->ib_qp.device, "bad resource type=%x qp=num=%x",
+                        rsrc_type, qp->ib_qp.qp_num);
+               return -EINVAL;
        }
-       get_page(mypage);
 
-       return mypage;
+       return 0;
 }
 
-static struct vm_operations_struct ehcau_vm_ops = {
-       .nopage = ehca_nopage,
-};
-
 int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 {
        u64 fileoffset = vma->vm_pgoff << PAGE_SHIFT;
@@ -175,7 +253,6 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
        u32 rsrc_type = (fileoffset >> 24) & 0xF; /* sq,rq,cmnd_window */
        u32 cur_pid = current->tgid;
        u32 ret;
-       u64 vsize, physical;
        unsigned long flags;
        struct ehca_cq *cq;
        struct ehca_qp *qp;
@@ -201,44 +278,12 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
                if (!cq->ib_cq.uobject || cq->ib_cq.uobject->context != context)
                        return -EINVAL;
 
-               switch (rsrc_type) {
-               case 1: /* galpa fw handle */
-                       ehca_dbg(cq->ib_cq.device, "cq=%p cq triggerarea", cq);
-                       vma->vm_flags |= VM_RESERVED;
-                       vsize = vma->vm_end - vma->vm_start;
-                       if (vsize != EHCA_PAGESIZE) {
-                               ehca_err(cq->ib_cq.device, "invalid vsize=%lx",
-                                        vma->vm_end - vma->vm_start);
-                               return -EINVAL;
-                       }
-
-                       physical = cq->galpas.user.fw_handle;
-                       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-                       vma->vm_flags |= VM_IO | VM_RESERVED;
-
-                       ehca_dbg(cq->ib_cq.device,
-                                "vsize=%lx physical=%lx", vsize, physical);
-                       ret = remap_pfn_range(vma, vma->vm_start,
-                                             physical >> PAGE_SHIFT, vsize,
-                                             vma->vm_page_prot);
-                       if (ret) {
-                               ehca_err(cq->ib_cq.device,
-                                        "remap_pfn_range() failed ret=%x",
-                                        ret);
-                               return -ENOMEM;
-                       }
-                       break;
-
-               case 2: /* cq queue_addr */
-                       ehca_dbg(cq->ib_cq.device, "cq=%p cq q_addr", cq);
-                       vma->vm_flags |= VM_RESERVED;
-                       vma->vm_ops = &ehcau_vm_ops;
-                       break;
-
-               default:
-                       ehca_err(cq->ib_cq.device, "bad resource type %x",
-                                rsrc_type);
-                       return -EINVAL;
+               ret = ehca_mmap_cq(vma, cq, rsrc_type);
+               if (unlikely(ret)) {
+                       ehca_err(cq->ib_cq.device,
+                                "ehca_mmap_cq() failed rc=%x cq_num=%x",
+                                ret, cq->cq_number);
+                       return ret;
                }
                break;
 
@@ -262,50 +307,12 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
                if (!qp->ib_qp.uobject || qp->ib_qp.uobject->context != context)
                        return -EINVAL;
 
-               switch (rsrc_type) {
-               case 1: /* galpa fw handle */
-                       ehca_dbg(qp->ib_qp.device, "qp=%p qp triggerarea", qp);
-                       vma->vm_flags |= VM_RESERVED;
-                       vsize = vma->vm_end - vma->vm_start;
-                       if (vsize != EHCA_PAGESIZE) {
-                               ehca_err(qp->ib_qp.device, "invalid vsize=%lx",
-                                        vma->vm_end - vma->vm_start);
-                               return -EINVAL;
-                       }
-
-                       physical = qp->galpas.user.fw_handle;
-                       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-                       vma->vm_flags |= VM_IO | VM_RESERVED;
-
-                       ehca_dbg(qp->ib_qp.device, "vsize=%lx physical=%lx",
-                                vsize, physical);
-                       ret = remap_pfn_range(vma, vma->vm_start,
-                                             physical >> PAGE_SHIFT, vsize,
-                                             vma->vm_page_prot);
-                       if (ret) {
-                               ehca_err(qp->ib_qp.device,
-                                        "remap_pfn_range() failed ret=%x",
-                                        ret);
-                               return -ENOMEM;
-                       }
-                       break;
-
-               case 2: /* qp rqueue_addr */
-                       ehca_dbg(qp->ib_qp.device, "qp=%p qp rqueue_addr", qp);
-                       vma->vm_flags |= VM_RESERVED;
-                       vma->vm_ops = &ehcau_vm_ops;
-                       break;
-
-               case 3: /* qp squeue_addr */
-                       ehca_dbg(qp->ib_qp.device, "qp=%p qp squeue_addr", qp);
-                       vma->vm_flags |= VM_RESERVED;
-                       vma->vm_ops = &ehcau_vm_ops;
-                       break;
-
-               default:
-                       ehca_err(qp->ib_qp.device, "bad resource type %x",
-                                rsrc_type);
-                       return -EINVAL;
+               ret = ehca_mmap_qp(vma, qp, rsrc_type);
+               if (unlikely(ret)) {
+                       ehca_err(qp->ib_qp.device,
+                                "ehca_mmap_qp() failed rc=%x qp_num=%x",
+                                ret, qp->ib_qp.qp_num);
+                       return ret;
                }
                break;
 
@@ -316,77 +323,3 @@ int ehca_mmap(struct ib_ucontext *context, struct vm_area_struct *vma)
 
        return 0;
 }
-
-int ehca_mmap_nopage(u64 foffset, u64 length, void **mapped,
-                    struct vm_area_struct **vma)
-{
-       down_write(&current->mm->mmap_sem);
-       *mapped = (void*)do_mmap(NULL,0, length, PROT_WRITE,
-                                MAP_SHARED | MAP_ANONYMOUS,
-                                foffset);
-       up_write(&current->mm->mmap_sem);
-       if (!(*mapped)) {
-               ehca_gen_err("couldn't mmap foffset=%lx length=%lx",
-                            foffset, length);
-               return -EINVAL;
-       }
-
-       *vma = find_vma(current->mm, (u64)*mapped);
-       if (!(*vma)) {
-               down_write(&current->mm->mmap_sem);
-               do_munmap(current->mm, 0, length);
-               up_write(&current->mm->mmap_sem);
-               ehca_gen_err("couldn't find vma queue=%p", *mapped);
-               return -EINVAL;
-       }
-       (*vma)->vm_flags |= VM_RESERVED;
-       (*vma)->vm_ops = &ehcau_vm_ops;
-
-       return 0;
-}
-
-int ehca_mmap_register(u64 physical, void **mapped,
-                      struct vm_area_struct **vma)
-{
-       int ret;
-       unsigned long vsize;
-       /* ehca hw supports only 4k page */
-       ret = ehca_mmap_nopage(0, EHCA_PAGESIZE, mapped, vma);
-       if (ret) {
-               ehca_gen_err("could'nt mmap physical=%lx", physical);
-               return ret;
-       }
-
-       (*vma)->vm_flags |= VM_RESERVED;
-       vsize = (*vma)->vm_end - (*vma)->vm_start;
-       if (vsize != EHCA_PAGESIZE) {
-               ehca_gen_err("invalid vsize=%lx",
-                            (*vma)->vm_end - (*vma)->vm_start);
-               return -EINVAL;
-       }
-
-       (*vma)->vm_page_prot = pgprot_noncached((*vma)->vm_page_prot);
-       (*vma)->vm_flags |= VM_IO | VM_RESERVED;
-
-       ret = remap_pfn_range((*vma), (*vma)->vm_start,
-                             physical >> PAGE_SHIFT, vsize,
-                             (*vma)->vm_page_prot);
-       if (ret) {
-               ehca_gen_err("remap_pfn_range() failed ret=%x", ret);
-               return -ENOMEM;
-       }
-
-       return 0;
-
-}
-
-int ehca_munmap(unsigned long addr, size_t len) {
-       int ret = 0;
-       struct mm_struct *mm = current->mm;
-       if (mm) {
-               down_write(&mm->mmap_sem);
-               ret = do_munmap(mm, addr, len);
-               up_write(&mm->mmap_sem);
-       }
-       return ret;
-}
index 46c1c89..64f07b1 100644 (file)
@@ -379,7 +379,7 @@ void ipath_error_qp(struct ipath_qp *qp, enum ib_wc_status err)
        wc.vendor_err = 0;
        wc.byte_len = 0;
        wc.imm_data = 0;
-       wc.qp_num = qp->ibqp.qp_num;
+       wc.qp = &qp->ibqp;
        wc.src_qp = 0;
        wc.wc_flags = 0;
        wc.pkey_index = 0;
index ce60387..5ff20cb 100644 (file)
@@ -702,7 +702,7 @@ void ipath_restart_rc(struct ipath_qp *qp, u32 psn, struct ib_wc *wc)
                wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
                wc->vendor_err = 0;
                wc->byte_len = 0;
-               wc->qp_num = qp->ibqp.qp_num;
+               wc->qp = &qp->ibqp;
                wc->src_qp = qp->remote_qpn;
                wc->pkey_index = 0;
                wc->slid = qp->remote_ah_attr.dlid;
@@ -836,7 +836,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
                        wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
                        wc.vendor_err = 0;
                        wc.byte_len = wqe->length;
-                       wc.qp_num = qp->ibqp.qp_num;
+                       wc.qp = &qp->ibqp;
                        wc.src_qp = qp->remote_qpn;
                        wc.pkey_index = 0;
                        wc.slid = qp->remote_ah_attr.dlid;
@@ -951,7 +951,7 @@ static int do_rc_ack(struct ipath_qp *qp, u32 aeth, u32 psn, int opcode)
                        wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
                        wc.vendor_err = 0;
                        wc.byte_len = 0;
-                       wc.qp_num = qp->ibqp.qp_num;
+                       wc.qp = &qp->ibqp;
                        wc.src_qp = qp->remote_qpn;
                        wc.pkey_index = 0;
                        wc.slid = qp->remote_ah_attr.dlid;
@@ -1511,7 +1511,7 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
                wc.status = IB_WC_SUCCESS;
                wc.opcode = IB_WC_RECV;
                wc.vendor_err = 0;
-               wc.qp_num = qp->ibqp.qp_num;
+               wc.qp = &qp->ibqp;
                wc.src_qp = qp->remote_qpn;
                wc.pkey_index = 0;
                wc.slid = qp->remote_ah_attr.dlid;
index f753051..e86cb17 100644 (file)
@@ -137,7 +137,7 @@ bad_lkey:
        wc.vendor_err = 0;
        wc.byte_len = 0;
        wc.imm_data = 0;
-       wc.qp_num = qp->ibqp.qp_num;
+       wc.qp = &qp->ibqp;
        wc.src_qp = 0;
        wc.wc_flags = 0;
        wc.pkey_index = 0;
@@ -336,7 +336,7 @@ again:
                        wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
                        wc.vendor_err = 0;
                        wc.byte_len = 0;
-                       wc.qp_num = sqp->ibqp.qp_num;
+                       wc.qp = &sqp->ibqp;
                        wc.src_qp = sqp->remote_qpn;
                        wc.pkey_index = 0;
                        wc.slid = sqp->remote_ah_attr.dlid;
@@ -426,7 +426,7 @@ again:
        wc.status = IB_WC_SUCCESS;
        wc.vendor_err = 0;
        wc.byte_len = wqe->length;
-       wc.qp_num = qp->ibqp.qp_num;
+       wc.qp = &qp->ibqp;
        wc.src_qp = qp->remote_qpn;
        /* XXX do we know which pkey matched? Only needed for GSI. */
        wc.pkey_index = 0;
@@ -447,7 +447,7 @@ send_comp:
                wc.opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
                wc.vendor_err = 0;
                wc.byte_len = wqe->length;
-               wc.qp_num = sqp->ibqp.qp_num;
+               wc.qp = &sqp->ibqp;
                wc.src_qp = 0;
                wc.pkey_index = 0;
                wc.slid = 0;
index e636cfd..325d663 100644 (file)
@@ -49,7 +49,7 @@ static void complete_last_send(struct ipath_qp *qp, struct ipath_swqe *wqe,
                wc->opcode = ib_ipath_wc_opcode[wqe->wr.opcode];
                wc->vendor_err = 0;
                wc->byte_len = wqe->length;
-               wc->qp_num = qp->ibqp.qp_num;
+               wc->qp = &qp->ibqp;
                wc->src_qp = qp->remote_qpn;
                wc->pkey_index = 0;
                wc->slid = qp->remote_ah_attr.dlid;
@@ -411,7 +411,7 @@ void ipath_uc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
                wc.status = IB_WC_SUCCESS;
                wc.opcode = IB_WC_RECV;
                wc.vendor_err = 0;
-               wc.qp_num = qp->ibqp.qp_num;
+               wc.qp = &qp->ibqp;
                wc.src_qp = qp->remote_qpn;
                wc.pkey_index = 0;
                wc.slid = qp->remote_ah_attr.dlid;
index 49f1102..9a3e546 100644 (file)
@@ -66,7 +66,7 @@ bad_lkey:
        wc.vendor_err = 0;
        wc.byte_len = 0;
        wc.imm_data = 0;
-       wc.qp_num = qp->ibqp.qp_num;
+       wc.qp = &qp->ibqp;
        wc.src_qp = 0;
        wc.wc_flags = 0;
        wc.pkey_index = 0;
@@ -255,7 +255,7 @@ static void ipath_ud_loopback(struct ipath_qp *sqp,
        wc->status = IB_WC_SUCCESS;
        wc->opcode = IB_WC_RECV;
        wc->vendor_err = 0;
-       wc->qp_num = qp->ibqp.qp_num;
+       wc->qp = &qp->ibqp;
        wc->src_qp = sqp->ibqp.qp_num;
        /* XXX do we know which pkey matched? Only needed for GSI. */
        wc->pkey_index = 0;
@@ -474,7 +474,7 @@ done:
                wc.vendor_err = 0;
                wc.opcode = IB_WC_SEND;
                wc.byte_len = len;
-               wc.qp_num = qp->ibqp.qp_num;
+               wc.qp = &qp->ibqp;
                wc.src_qp = 0;
                wc.wc_flags = 0;
                /* XXX initialize other fields? */
@@ -651,7 +651,7 @@ void ipath_ud_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
        wc.status = IB_WC_SUCCESS;
        wc.opcode = IB_WC_RECV;
        wc.vendor_err = 0;
-       wc.qp_num = qp->ibqp.qp_num;
+       wc.qp = &qp->ibqp;
        wc.src_qp = src_qp;
        /* XXX do we know which pkey matched? Only needed for GSI. */
        wc.pkey_index = 0;
index 768df72..968d151 100644 (file)
@@ -1854,7 +1854,7 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
 
                memset(inbox + 256, 0, 256);
 
-               MTHCA_PUT(inbox, in_wc->qp_num,     MAD_IFC_MY_QPN_OFFSET);
+               MTHCA_PUT(inbox, in_wc->qp->qp_num, MAD_IFC_MY_QPN_OFFSET);
                MTHCA_PUT(inbox, in_wc->src_qp,     MAD_IFC_RQPN_OFFSET);
 
                val = in_wc->sl << 4;
index 1159c8a..efd79ef 100644 (file)
@@ -534,7 +534,7 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
                }
        }
 
-       entry->qp_num = (*cur_qp)->qpn;
+       entry->qp = &(*cur_qp)->ibqp;
 
        if (is_send) {
                wq = &(*cur_qp)->sq;
index 705eb1d..af5ee2e 100644 (file)
@@ -958,16 +958,17 @@ struct ipoib_dev_priv *ipoib_intf_alloc(const char *name)
        return netdev_priv(dev);
 }
 
-static ssize_t show_pkey(struct class_device *cdev, char *buf)
+static ssize_t show_pkey(struct device *dev,
+                        struct device_attribute *attr, char *buf)
 {
-       struct ipoib_dev_priv *priv =
-               netdev_priv(container_of(cdev, struct net_device, class_dev));
+       struct ipoib_dev_priv *priv = netdev_priv(to_net_dev(dev));
 
        return sprintf(buf, "0x%04x\n", priv->pkey);
 }
-static CLASS_DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
+static DEVICE_ATTR(pkey, S_IRUGO, show_pkey, NULL);
 
-static ssize_t create_child(struct class_device *cdev,
+static ssize_t create_child(struct device *dev,
+                           struct device_attribute *attr,
                            const char *buf, size_t count)
 {
        int pkey;
@@ -985,14 +986,14 @@ static ssize_t create_child(struct class_device *cdev,
         */
        pkey |= 0x8000;
 
-       ret = ipoib_vlan_add(container_of(cdev, struct net_device, class_dev),
-                            pkey);
+       ret = ipoib_vlan_add(to_net_dev(dev), pkey);
 
        return ret ? ret : count;
 }
-static CLASS_DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child);
+static DEVICE_ATTR(create_child, S_IWUGO, NULL, create_child);
 
-static ssize_t delete_child(struct class_device *cdev,
+static ssize_t delete_child(struct device *dev,
+                           struct device_attribute *attr,
                            const char *buf, size_t count)
 {
        int pkey;
@@ -1004,18 +1005,16 @@ static ssize_t delete_child(struct class_device *cdev,
        if (pkey < 0 || pkey > 0xffff)
                return -EINVAL;
 
-       ret = ipoib_vlan_delete(container_of(cdev, struct net_device, class_dev),
-                               pkey);
+       ret = ipoib_vlan_delete(to_net_dev(dev), pkey);
 
        return ret ? ret : count;
 
 }
-static CLASS_DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child);
+static DEVICE_ATTR(delete_child, S_IWUGO, NULL, delete_child);
 
 int ipoib_add_pkey_attr(struct net_device *dev)
 {
-       return class_device_create_file(&dev->class_dev,
-                                       &class_device_attr_pkey);
+       return device_create_file(&dev->dev, &dev_attr_pkey);
 }
 
 static struct net_device *ipoib_add_port(const char *format,
@@ -1083,11 +1082,9 @@ static struct net_device *ipoib_add_port(const char *format,
 
        if (ipoib_add_pkey_attr(priv->dev))
                goto sysfs_failed;
-       if (class_device_create_file(&priv->dev->class_dev,
-                                    &class_device_attr_create_child))
+       if (device_create_file(&priv->dev->dev, &dev_attr_create_child))
                goto sysfs_failed;
-       if (class_device_create_file(&priv->dev->class_dev,
-                                    &class_device_attr_delete_child))
+       if (device_create_file(&priv->dev->dev, &dev_attr_delete_child))
                goto sysfs_failed;
 
        return priv->dev;
index f887780..085eafe 100644 (file)
 
 #include "ipoib.h"
 
-static ssize_t show_parent(struct class_device *class_dev, char *buf)
+static ssize_t show_parent(struct device *d, struct device_attribute *attr,
+                          char *buf)
 {
-       struct net_device *dev =
-               container_of(class_dev, struct net_device, class_dev);
+       struct net_device *dev = to_net_dev(d);
        struct ipoib_dev_priv *priv = netdev_priv(dev);
 
        return sprintf(buf, "%s\n", priv->parent->name);
 }
-static CLASS_DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
+static DEVICE_ATTR(parent, S_IRUGO, show_parent, NULL);
 
 int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
 {
@@ -118,8 +118,7 @@ int ipoib_vlan_add(struct net_device *pdev, unsigned short pkey)
        if (ipoib_add_pkey_attr(priv->dev))
                goto sysfs_failed;
 
-       if (class_device_create_file(&priv->dev->class_dev,
-                                    &class_device_attr_parent))
+       if (device_create_file(&priv->dev->dev, &dev_attr_parent))
                goto sysfs_failed;
 
        list_add_tail(&priv->list, &ppriv->child_intfs);
index 72611fd..5e8ac57 100644 (file)
@@ -548,6 +548,7 @@ static int srp_reconnect_target(struct srp_target_port *target)
        target->tx_head  = 0;
        target->tx_tail  = 0;
 
+       target->qp_in_error = 0;
        ret = srp_connect_target(target);
        if (ret)
                goto err;
@@ -878,6 +879,7 @@ static void srp_completion(struct ib_cq *cq, void *target_ptr)
                        printk(KERN_ERR PFX "failed %s status %d\n",
                               wc.wr_id & SRP_OP_RECV ? "receive" : "send",
                               wc.status);
+                       target->qp_in_error = 1;
                        break;
                }
 
@@ -1337,6 +1339,8 @@ static int srp_abort(struct scsi_cmnd *scmnd)
 
        printk(KERN_ERR "SRP abort called\n");
 
+       if (target->qp_in_error)
+               return FAILED;
        if (srp_find_req(target, scmnd, &req))
                return FAILED;
        if (srp_send_tsk_mgmt(target, req, SRP_TSK_ABORT_TASK))
@@ -1365,6 +1369,8 @@ static int srp_reset_device(struct scsi_cmnd *scmnd)
 
        printk(KERN_ERR "SRP reset_device called\n");
 
+       if (target->qp_in_error)
+               return FAILED;
        if (srp_find_req(target, scmnd, &req))
                return FAILED;
        if (srp_send_tsk_mgmt(target, req, SRP_TSK_LUN_RESET))
@@ -1801,6 +1807,7 @@ static ssize_t srp_create_target(struct class_device *class_dev,
                goto err_free;
        }
 
+       target->qp_in_error = 0;
        ret = srp_connect_target(target);
        if (ret) {
                printk(KERN_ERR PFX "Connection failed\n");
index c217723..2f3319c 100644 (file)
@@ -158,6 +158,7 @@ struct srp_target_port {
        struct completion       done;
        int                     status;
        enum srp_target_state   state;
+       int                     qp_in_error;
 };
 
 struct srp_iu {
index f0ce822..17c8c63 100644 (file)
@@ -45,7 +45,7 @@ EXPORT_SYMBOL(serio_interrupt);
 EXPORT_SYMBOL(__serio_register_port);
 EXPORT_SYMBOL(serio_unregister_port);
 EXPORT_SYMBOL(serio_unregister_child_port);
-EXPORT_SYMBOL(serio_register_driver);
+EXPORT_SYMBOL(__serio_register_driver);
 EXPORT_SYMBOL(serio_unregister_driver);
 EXPORT_SYMBOL(serio_open);
 EXPORT_SYMBOL(serio_close);
@@ -789,12 +789,14 @@ static void serio_attach_driver(struct serio_driver *drv)
                        drv->driver.name, error);
 }
 
-int serio_register_driver(struct serio_driver *drv)
+int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name)
 {
        int manual_bind = drv->manual_bind;
        int error;
 
        drv->driver.bus = &serio_bus;
+       drv->driver.owner = owner;
+       drv->driver.mod_name = mod_name;
 
        /*
         * Temporarily disable automatic binding because probing
index 4363a91..3daf049 100644 (file)
@@ -75,7 +75,6 @@ static const struct usb_device_id zc0301_id_table[] =  {                      \
        { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
        { ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */           \
        { ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */           \
-       { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
        { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
        { ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */    \
        { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */           \
index 00db31c..89bba27 100644 (file)
@@ -69,6 +69,25 @@ config TIFM_7XX1
           To compile this driver as a module, choose M here: the module will
          be called tifm_7xx1.
 
+config ASUS_LAPTOP
+        tristate "Asus Laptop Extras (EXPERIMENTAL)"
+        depends on X86
+        depends on ACPI
+       depends on EXPERIMENTAL && !ACPI_ASUS
+       depends on LEDS_CLASS
+       depends on BACKLIGHT_CLASS_DEVICE
+        ---help---
+         This is the new Linux driver for Asus laptops. It may also support some
+         MEDION, JVC or VICTOR laptops. It makes all the extra buttons generate
+         standard ACPI events that go through /proc/acpi/events. It also adds
+         support for video output switching, LCD backlight control, Bluetooth and
+         Wlan control, and most importantly, allows you to blink those fancy LEDs.
+
+         For more information and a userspace daemon for handling the extra
+         buttons see <http://acpi4asus.sf.net/>.
+
+         If you have an ACPI-compatible ASUS laptop, say Y or M here.
+
 config MSI_LAPTOP
         tristate "MSI Laptop Extras"
         depends on X86
index c9e98ab..35da53c 100644 (file)
@@ -6,6 +6,7 @@ obj- := misc.o  # Dummy rule to force built-in.o to be made
 obj-$(CONFIG_IBM_ASM)          += ibmasm/
 obj-$(CONFIG_HDPU_FEATURES)    += hdpuftrs/
 obj-$(CONFIG_MSI_LAPTOP)     += msi-laptop.o
+obj-$(CONFIG_ASUS_LAPTOP)     += asus-laptop.o
 obj-$(CONFIG_LKDTM)            += lkdtm.o
 obj-$(CONFIG_TIFM_CORE)        += tifm_core.o
 obj-$(CONFIG_TIFM_7XX1)        += tifm_7xx1.o
diff --git a/drivers/misc/asus-laptop.c b/drivers/misc/asus-laptop.c
new file mode 100644 (file)
index 0000000..861c399
--- /dev/null
@@ -0,0 +1,1165 @@
+/*
+ *  asus-laptop.c - Asus Laptop Support
+ *
+ *
+ *  Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
+ *  Copyright (C) 2006 Corentin Chary
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  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
+ *
+ *
+ *  The development page for this driver is located at
+ *  http://sourceforge.net/projects/acpi4asus/
+ *
+ *  Credits:
+ *  Pontus Fuchs   - Helper functions, cleanup
+ *  Johann Wiesner - Small compile fixes
+ *  John Belmonte  - ACPI code for Toshiba laptop was a good starting point.
+ *  Eric Burghard  - LED display support for W1N
+ *  Josh Green     - Light Sens support
+ *  Thomas Tuttle  - His first patch for led support was very helpfull
+ *
+ */
+
+#include <linux/autoconf.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/err.h>
+#include <linux/proc_fs.h>
+#include <linux/backlight.h>
+#include <linux/fb.h>
+#include <linux/leds.h>
+#include <linux/platform_device.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+#include <asm/uaccess.h>
+
+#define ASUS_LAPTOP_VERSION "0.40"
+
+#define ASUS_HOTK_NAME          "Asus Laptop Support"
+#define ASUS_HOTK_CLASS         "hotkey"
+#define ASUS_HOTK_DEVICE_NAME   "Hotkey"
+#define ASUS_HOTK_HID           "ATK0100"
+#define ASUS_HOTK_FILE          "asus-laptop"
+#define ASUS_HOTK_PREFIX        "\\_SB.ATKD."
+
+/*
+ * Some events we use, same for all Asus
+ */
+#define ATKD_BR_UP       0x10
+#define ATKD_BR_DOWN     0x20
+#define ATKD_LCD_ON      0x33
+#define ATKD_LCD_OFF     0x34
+
+/*
+ * Known bits returned by \_SB.ATKD.HWRS
+ */
+#define WL_HWRS     0x80
+#define BT_HWRS     0x100
+
+/*
+ * Flags for hotk status
+ * WL_ON and BT_ON are also used for wireless_status()
+ */
+#define WL_ON       0x01       //internal Wifi
+#define BT_ON       0x02       //internal Bluetooth
+#define MLED_ON     0x04       //mail LED
+#define TLED_ON     0x08       //touchpad LED
+#define RLED_ON     0x10       //Record LED
+#define PLED_ON     0x20       //Phone LED
+#define LCD_ON      0x40       //LCD backlight
+
+#define ASUS_LOG    ASUS_HOTK_FILE ": "
+#define ASUS_ERR    KERN_ERR    ASUS_LOG
+#define ASUS_WARNING    KERN_WARNING    ASUS_LOG
+#define ASUS_NOTICE KERN_NOTICE ASUS_LOG
+#define ASUS_INFO   KERN_INFO   ASUS_LOG
+#define ASUS_DEBUG  KERN_DEBUG  ASUS_LOG
+
+MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
+MODULE_DESCRIPTION(ASUS_HOTK_NAME);
+MODULE_LICENSE("GPL");
+
+#define ASUS_HANDLE(object, paths...)                                  \
+       static acpi_handle  object##_handle = NULL;                     \
+       static char *object##_paths[] = { paths }
+
+/* LED */
+ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED");
+ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED");
+ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED");        /* W1JC */
+ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED");        /* A7J */
+
+/* LEDD */
+ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");
+
+/* Bluetooth and WLAN
+ * WLED and BLED are not handled like other XLED, because in some dsdt
+ * they also control the WLAN/Bluetooth device.
+ */
+ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED");
+ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED");
+ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS"); /* All new models */
+
+/* Brightness */
+ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV");
+ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "GPLV");
+
+/* Backlight */
+ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10",    /* All new models */
+           "\\_SB.PCI0.ISA.EC0._Q10",  /* A1x */
+           "\\_SB.PCI0.PX40.ECD0._Q10",        /* L3C */
+           "\\_SB.PCI0.PX40.EC0.Q10",  /* M1A */
+           "\\_SB.PCI0.LPCB.EC0._Q10", /* P30 */
+           "\\_SB.PCI0.PX40.Q10",      /* S1x */
+           "\\Q10");           /* A2x, L2D, L3D, M2E */
+
+/* Display */
+ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");
+ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD",   /*  A6B, A6K A6R A7D F3JM L4R M6R A3G
+                                                          M6A M6V VX-1 V6J V6V W3Z */
+           "\\_SB.PCI0.P0P2.VGA.GETD", /* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V
+                                          S5A M5A z33A W1Jc W2V */
+           "\\_SB.PCI0.P0P3.VGA.GETD", /* A6V A6Q */
+           "\\_SB.PCI0.P0PA.VGA.GETD", /* A6T, A6M */
+           "\\_SB.PCI0.PCI1.VGAC.NMAP",        /* L3C */
+           "\\_SB.PCI0.VGA.GETD",      /* Z96F */
+           "\\ACTD",           /* A2D */
+           "\\ADVG",           /* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */
+           "\\DNXT",           /* P30 */
+           "\\INFB",           /* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */
+           "\\SSTE");          /* A3F A6F A3N A3L M6N W3N W6A */
+
+ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC");       /* Z71A Z71V */
+ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL");        /* Z71A Z71V */
+
+/*
+ * This is the main structure, we can use it to store anything interesting
+ * about the hotk device
+ */
+struct asus_hotk {
+       char *name;             //laptop name
+       struct acpi_device *device;     //the device we are in
+       acpi_handle handle;     //the handle of the hotk device
+       char status;            //status of the hotk, for LEDs, ...
+       u32 ledd_status;        //status of the LED display
+       u8 light_level;         //light sensor level
+       u8 light_switch;        //light sensor switch value
+       u16 event_count[128];   //count for each event TODO make this better
+};
+
+/*
+ * This header is made available to allow proper configuration given model,
+ * revision number , ... this info cannot go in struct asus_hotk because it is
+ * available before the hotk
+ */
+static struct acpi_table_header *asus_info;
+
+/* The actual device the driver binds to */
+static struct asus_hotk *hotk;
+
+/*
+ * The hotkey driver declaration
+ */
+static int asus_hotk_add(struct acpi_device *device);
+static int asus_hotk_remove(struct acpi_device *device, int type);
+static struct acpi_driver asus_hotk_driver = {
+       .name = ASUS_HOTK_NAME,
+       .class = ASUS_HOTK_CLASS,
+       .ids = ASUS_HOTK_HID,
+       .ops = {
+               .add = asus_hotk_add,
+               .remove = asus_hotk_remove,
+               },
+};
+
+/* The backlight device /sys/class/backlight */
+static struct backlight_device *asus_backlight_device;
+
+/*
+ * The backlight class declaration
+ */
+static int read_brightness(struct backlight_device *bd);
+static int update_bl_status(struct backlight_device *bd);
+static struct backlight_properties asusbl_data = {
+       .owner = THIS_MODULE,
+       .get_brightness = read_brightness,
+       .update_status = update_bl_status,
+       .max_brightness = 15,
+};
+
+/* These functions actually update the LED's, and are called from a
+ * workqueue. By doing this as separate work rather than when the LED
+ * subsystem asks, we avoid messing with the Asus ACPI stuff during a
+ * potentially bad time, such as a timer interrupt. */
+static struct workqueue_struct *led_workqueue;
+
+#define ASUS_LED(object, ledname)                                      \
+       static void object##_led_set(struct led_classdev *led_cdev,     \
+                                    enum led_brightness value);        \
+       static void object##_led_update(struct work_struct *ignored);   \
+       static int object##_led_wk;                                     \
+       DECLARE_WORK(object##_led_work, object##_led_update);           \
+       static struct led_classdev object##_led = {                     \
+               .name           = "asus:" ledname,                      \
+               .brightness_set = object##_led_set,                     \
+       }
+
+ASUS_LED(mled, "mail");
+ASUS_LED(tled, "touchpad");
+ASUS_LED(rled, "record");
+ASUS_LED(pled, "phone");
+
+/*
+ * This function evaluates an ACPI method, given an int as parameter, the
+ * method is searched within the scope of the handle, can be NULL. The output
+ * of the method is written is output, which can also be NULL
+ *
+ * returns 1 if write is successful, 0 else.
+ */
+static int write_acpi_int(acpi_handle handle, const char *method, int val,
+                         struct acpi_buffer *output)
+{
+       struct acpi_object_list params; //list of input parameters (an int here)
+       union acpi_object in_obj;       //the only param we use
+       acpi_status status;
+
+       params.count = 1;
+       params.pointer = &in_obj;
+       in_obj.type = ACPI_TYPE_INTEGER;
+       in_obj.integer.value = val;
+
+       status = acpi_evaluate_object(handle, (char *)method, &params, output);
+       return (status == AE_OK);
+}
+
+static int read_acpi_int(acpi_handle handle, const char *method, int *val,
+                        struct acpi_object_list *params)
+{
+       struct acpi_buffer output;
+       union acpi_object out_obj;
+       acpi_status status;
+
+       output.length = sizeof(out_obj);
+       output.pointer = &out_obj;
+
+       status = acpi_evaluate_object(handle, (char *)method, params, &output);
+       *val = out_obj.integer.value;
+       return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
+}
+
+static int read_wireless_status(int mask)
+{
+       int status;
+
+       if (!wireless_status_handle)
+               return (hotk->status & mask) ? 1 : 0;
+
+       if (read_acpi_int(wireless_status_handle, NULL, &status, NULL)) {
+               return (status & mask) ? 1 : 0;
+       } else
+               printk(ASUS_WARNING "Error reading Wireless status\n");
+
+       return (hotk->status & mask) ? 1 : 0;
+}
+
+/* Generic LED functions */
+static int read_status(int mask)
+{
+       /* There is a special method for both wireless devices */
+       if (mask == BT_ON || mask == WL_ON)
+               return read_wireless_status(mask);
+
+       return (hotk->status & mask) ? 1 : 0;
+}
+
+static void write_status(acpi_handle handle, int out, int mask, int invert)
+{
+       hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);
+
+       if (invert)             /* invert target value */
+               out = !out & 0x1;
+
+       if (handle && !write_acpi_int(handle, NULL, out, NULL))
+               printk(ASUS_WARNING " write failed\n");
+}
+
+/* /sys/class/led handlers */
+#define ASUS_LED_HANDLER(object, mask, invert)                         \
+       static void object##_led_set(struct led_classdev *led_cdev,     \
+                                    enum led_brightness value)         \
+       {                                                               \
+               object##_led_wk = value;                                \
+               queue_work(led_workqueue, &object##_led_work);          \
+       }                                                               \
+       static void object##_led_update(struct work_struct *ignored)    \
+       {                                                               \
+               int value = object##_led_wk;                            \
+               write_status(object##_set_handle, value, (mask), (invert)); \
+       }
+
+ASUS_LED_HANDLER(mled, MLED_ON, 1);
+ASUS_LED_HANDLER(pled, PLED_ON, 0);
+ASUS_LED_HANDLER(rled, RLED_ON, 0);
+ASUS_LED_HANDLER(tled, TLED_ON, 0);
+
+static int get_lcd_state(void)
+{
+       return read_status(LCD_ON);
+}
+
+static int set_lcd_state(int value)
+{
+       int lcd = 0;
+       acpi_status status = 0;
+
+       lcd = value ? 1 : 0;
+
+       if (lcd == get_lcd_state())
+               return 0;
+
+       if (lcd_switch_handle) {
+               status = acpi_evaluate_object(lcd_switch_handle,
+                                             NULL, NULL, NULL);
+
+               if (ACPI_FAILURE(status))
+                       printk(ASUS_WARNING "Error switching LCD\n");
+       }
+
+       write_status(NULL, lcd, LCD_ON, 0);
+       return 0;
+}
+
+static void lcd_blank(int blank)
+{
+       struct backlight_device *bd = asus_backlight_device;
+
+       if (bd) {
+               down(&bd->sem);
+               if (likely(bd->props)) {
+                       bd->props->power = blank;
+                       if (likely(bd->props->update_status))
+                               bd->props->update_status(bd);
+               }
+               up(&bd->sem);
+       }
+}
+
+static int read_brightness(struct backlight_device *bd)
+{
+       int value;
+
+       if (!read_acpi_int(brightness_get_handle, NULL, &value, NULL))
+               printk(ASUS_WARNING "Error reading brightness\n");
+
+       return value;
+}
+
+static int set_brightness(struct backlight_device *bd, int value)
+{
+       int ret = 0;
+
+       value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
+       /* 0 <= value <= 15 */
+
+       if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) {
+               printk(ASUS_WARNING "Error changing brightness\n");
+               ret = -EIO;
+       }
+
+       return ret;
+}
+
+static int update_bl_status(struct backlight_device *bd)
+{
+       int rv;
+       int value = bd->props->brightness;
+
+       rv = set_brightness(bd, value);
+       if (rv)
+               return rv;
+
+       value = (bd->props->power == FB_BLANK_UNBLANK) ? 1 : 0;
+       return set_lcd_state(value);
+}
+
+/*
+ * Platform device handlers
+ */
+
+/*
+ * We write our info in page, we begin at offset off and cannot write more
+ * than count bytes. We set eof to 1 if we handle those 2 values. We return the
+ * number of bytes written in page
+ */
+static ssize_t show_infos(struct device *dev,
+                         struct device_attribute *attr, char *page)
+{
+       int len = 0;
+       int temp;
+       char buf[16];           //enough for all info
+       /*
+        * We use the easy way, we don't care of off and count, so we don't set eof
+        * to 1
+        */
+
+       len += sprintf(page, ASUS_HOTK_NAME " " ASUS_LAPTOP_VERSION "\n");
+       len += sprintf(page + len, "Model reference    : %s\n", hotk->name);
+       /*
+        * The SFUN method probably allows the original driver to get the list
+        * of features supported by a given model. For now, 0x0100 or 0x0800
+        * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
+        * The significance of others is yet to be found.
+        */
+       if (read_acpi_int(hotk->handle, "SFUN", &temp, NULL))
+               len +=
+                   sprintf(page + len, "SFUN value         : 0x%04x\n", temp);
+       /*
+        * Another value for userspace: the ASYM method returns 0x02 for
+        * battery low and 0x04 for battery critical, its readings tend to be
+        * more accurate than those provided by _BST.
+        * Note: since not all the laptops provide this method, errors are
+        * silently ignored.
+        */
+       if (read_acpi_int(hotk->handle, "ASYM", &temp, NULL))
+               len +=
+                   sprintf(page + len, "ASYM value         : 0x%04x\n", temp);
+       if (asus_info) {
+               snprintf(buf, 16, "%d", asus_info->length);
+               len += sprintf(page + len, "DSDT length        : %s\n", buf);
+               snprintf(buf, 16, "%d", asus_info->checksum);
+               len += sprintf(page + len, "DSDT checksum      : %s\n", buf);
+               snprintf(buf, 16, "%d", asus_info->revision);
+               len += sprintf(page + len, "DSDT revision      : %s\n", buf);
+               snprintf(buf, 7, "%s", asus_info->oem_id);
+               len += sprintf(page + len, "OEM id             : %s\n", buf);
+               snprintf(buf, 9, "%s", asus_info->oem_table_id);
+               len += sprintf(page + len, "OEM table id       : %s\n", buf);
+               snprintf(buf, 16, "%x", asus_info->oem_revision);
+               len += sprintf(page + len, "OEM revision       : 0x%s\n", buf);
+               snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
+               len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
+               snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
+               len += sprintf(page + len, "ASL comp revision  : 0x%s\n", buf);
+       }
+
+       return len;
+}
+
+static int parse_arg(const char *buf, unsigned long count, int *val)
+{
+       if (!count)
+               return 0;
+       if (count > 31)
+               return -EINVAL;
+       if (sscanf(buf, "%i", val) != 1)
+               return -EINVAL;
+       return count;
+}
+
+static ssize_t store_status(const char *buf, size_t count,
+                           acpi_handle handle, int mask, int invert)
+{
+       int rv, value;
+       int out = 0;
+
+       rv = parse_arg(buf, count, &value);
+       if (rv > 0)
+               out = value ? 1 : 0;
+
+       write_status(handle, out, mask, invert);
+
+       return rv;
+}
+
+/*
+ * LEDD display
+ */
+static ssize_t show_ledd(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "0x%08x\n", hotk->ledd_status);
+}
+
+static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       int rv, value;
+
+       rv = parse_arg(buf, count, &value);
+       if (rv > 0) {
+               if (!write_acpi_int(ledd_set_handle, NULL, value, NULL))
+                       printk(ASUS_WARNING "LED display write failed\n");
+               else
+                       hotk->ledd_status = (u32) value;
+       }
+       return rv;
+}
+
+/*
+ * WLAN
+ */
+static ssize_t show_wlan(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", read_status(WL_ON));
+}
+
+static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       return store_status(buf, count, wl_switch_handle, WL_ON, 0);
+}
+
+/*
+ * Bluetooth
+ */
+static ssize_t show_bluetooth(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", read_status(BT_ON));
+}
+
+static ssize_t store_bluetooth(struct device *dev,
+                              struct device_attribute *attr, const char *buf,
+                              size_t count)
+{
+       return store_status(buf, count, bt_switch_handle, BT_ON, 0);
+}
+
+/*
+ * Display
+ */
+static void set_display(int value)
+{
+       /* no sanity check needed for now */
+       if (!write_acpi_int(display_set_handle, NULL, value, NULL))
+               printk(ASUS_WARNING "Error setting display\n");
+       return;
+}
+
+static int read_display(void)
+{
+       int value = 0;
+
+       /* In most of the case, we know how to set the display, but sometime
+          we can't read it */
+       if (display_get_handle) {
+               if (!read_acpi_int(display_get_handle, NULL, &value, NULL))
+                       printk(ASUS_WARNING "Error reading display status\n");
+       }
+
+       value &= 0x0F;          /* needed for some models, shouldn't hurt others */
+
+       return value;
+}
+
+/*
+ * Now, *this* one could be more user-friendly, but so far, no-one has
+ * complained. The significance of bits is the same as in store_disp()
+ */
+static ssize_t show_disp(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", read_display());
+}
+
+/*
+ * Experimental support for display switching. As of now: 1 should activate
+ * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI.
+ * Any combination (bitwise) of these will suffice. I never actually tested 4
+ * displays hooked up simultaneously, so be warned. See the acpi4asus README
+ * for more info.
+ */
+static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       int rv, value;
+
+       rv = parse_arg(buf, count, &value);
+       if (rv > 0)
+               set_display(value);
+       return rv;
+}
+
+/*
+ * Light Sens
+ */
+static void set_light_sens_switch(int value)
+{
+       if (!write_acpi_int(ls_switch_handle, NULL, value, NULL))
+               printk(ASUS_WARNING "Error setting light sensor switch\n");
+       hotk->light_switch = value;
+}
+
+static ssize_t show_lssw(struct device *dev,
+                        struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", hotk->light_switch);
+}
+
+static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t count)
+{
+       int rv, value;
+
+       rv = parse_arg(buf, count, &value);
+       if (rv > 0)
+               set_light_sens_switch(value ? 1 : 0);
+
+       return rv;
+}
+
+static void set_light_sens_level(int value)
+{
+       if (!write_acpi_int(ls_level_handle, NULL, value, NULL))
+               printk(ASUS_WARNING "Error setting light sensor level\n");
+       hotk->light_level = value;
+}
+
+static ssize_t show_lslvl(struct device *dev,
+                         struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", hotk->light_level);
+}
+
+static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t count)
+{
+       int rv, value;
+
+       rv = parse_arg(buf, count, &value);
+       if (rv > 0) {
+               value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
+               /* 0 <= value <= 15 */
+               set_light_sens_level(value);
+       }
+
+       return rv;
+}
+
+static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
+{
+       /* TODO Find a better way to handle events count. */
+       if (!hotk)
+               return;
+
+       /*
+        * We need to tell the backlight device when the backlight power is
+        * switched
+        */
+       if (event == ATKD_LCD_ON) {
+               write_status(NULL, 1, LCD_ON, 0);
+               lcd_blank(FB_BLANK_UNBLANK);
+       } else if (event == ATKD_LCD_OFF) {
+               write_status(NULL, 0, LCD_ON, 0);
+               lcd_blank(FB_BLANK_POWERDOWN);
+       }
+
+       acpi_bus_generate_event(hotk->device, event,
+                               hotk->event_count[event % 128]++);
+
+       return;
+}
+
+#define ASUS_CREATE_DEVICE_ATTR(_name)                                 \
+       struct device_attribute dev_attr_##_name = {                    \
+               .attr = {                                               \
+                       .name = __stringify(_name),                     \
+                       .mode = 0,                                      \
+                       .owner = THIS_MODULE },                         \
+               .show   = NULL,                                         \
+               .store  = NULL,                                         \
+       }
+
+#define ASUS_SET_DEVICE_ATTR(_name, _mode, _show, _store)              \
+       do {                                                            \
+               dev_attr_##_name.attr.mode = _mode;                     \
+               dev_attr_##_name.show = _show;                          \
+               dev_attr_##_name.store = _store;                        \
+       } while(0)
+
+static ASUS_CREATE_DEVICE_ATTR(infos);
+static ASUS_CREATE_DEVICE_ATTR(wlan);
+static ASUS_CREATE_DEVICE_ATTR(bluetooth);
+static ASUS_CREATE_DEVICE_ATTR(display);
+static ASUS_CREATE_DEVICE_ATTR(ledd);
+static ASUS_CREATE_DEVICE_ATTR(ls_switch);
+static ASUS_CREATE_DEVICE_ATTR(ls_level);
+
+static struct attribute *asuspf_attributes[] = {
+       &dev_attr_infos.attr,
+       &dev_attr_wlan.attr,
+       &dev_attr_bluetooth.attr,
+       &dev_attr_display.attr,
+       &dev_attr_ledd.attr,
+       &dev_attr_ls_switch.attr,
+       &dev_attr_ls_level.attr,
+       NULL
+};
+
+static struct attribute_group asuspf_attribute_group = {
+       .attrs = asuspf_attributes
+};
+
+static struct platform_driver asuspf_driver = {
+       .driver = {
+                  .name = ASUS_HOTK_FILE,
+                  .owner = THIS_MODULE,
+                  }
+};
+
+static struct platform_device *asuspf_device;
+
+static void asus_hotk_add_fs(void)
+{
+       ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL);
+
+       if (wl_switch_handle)
+               ASUS_SET_DEVICE_ATTR(wlan, 0644, show_wlan, store_wlan);
+
+       if (bt_switch_handle)
+               ASUS_SET_DEVICE_ATTR(bluetooth, 0644,
+                                    show_bluetooth, store_bluetooth);
+
+       if (display_set_handle && display_get_handle)
+               ASUS_SET_DEVICE_ATTR(display, 0644, show_disp, store_disp);
+       else if (display_set_handle)
+               ASUS_SET_DEVICE_ATTR(display, 0200, NULL, store_disp);
+
+       if (ledd_set_handle)
+               ASUS_SET_DEVICE_ATTR(ledd, 0644, show_ledd, store_ledd);
+
+       if (ls_switch_handle && ls_level_handle) {
+               ASUS_SET_DEVICE_ATTR(ls_level, 0644, show_lslvl, store_lslvl);
+               ASUS_SET_DEVICE_ATTR(ls_switch, 0644, show_lssw, store_lssw);
+       }
+}
+
+static int asus_handle_init(char *name, acpi_handle * handle,
+                           char **paths, int num_paths)
+{
+       int i;
+       acpi_status status;
+
+       for (i = 0; i < num_paths; i++) {
+               status = acpi_get_handle(NULL, paths[i], handle);
+               if (ACPI_SUCCESS(status))
+                       return 0;
+       }
+
+       *handle = NULL;
+       return -ENODEV;
+}
+
+#define ASUS_HANDLE_INIT(object)                                       \
+       asus_handle_init(#object, &object##_handle, object##_paths,     \
+                        ARRAY_SIZE(object##_paths))
+
+/*
+ * This function is used to initialize the hotk with right values. In this
+ * method, we can make all the detection we want, and modify the hotk struct
+ */
+static int asus_hotk_get_info(void)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *model = NULL;
+       int bsts_result, hwrs_result;
+       char *string = NULL;
+       acpi_status status;
+
+       /*
+        * Get DSDT headers early enough to allow for differentiating between
+        * models, but late enough to allow acpi_bus_register_driver() to fail
+        * before doing anything ACPI-specific. Should we encounter a machine,
+        * which needs special handling (i.e. its hotkey device has a different
+        * HID), this bit will be moved. A global variable asus_info contains
+        * the DSDT header.
+        */
+       status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
+       if (ACPI_FAILURE(status))
+               printk(ASUS_WARNING "Couldn't get the DSDT table header\n");
+
+       /* We have to write 0 on init this far for all ASUS models */
+       if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
+               printk(ASUS_ERR "Hotkey initialization failed\n");
+               return -ENODEV;
+       }
+
+       /* This needs to be called for some laptops to init properly */
+       if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result, NULL))
+               printk(ASUS_WARNING "Error calling BSTS\n");
+       else if (bsts_result)
+               printk(ASUS_NOTICE "BSTS called, 0x%02x returned\n",
+                      bsts_result);
+
+       /*
+        * Try to match the object returned by INIT to the specific model.
+        * Handle every possible object (or the lack of thereof) the DSDT
+        * writers might throw at us. When in trouble, we pass NULL to
+        * asus_model_match() and try something completely different.
+        */
+       if (buffer.pointer) {
+               model = buffer.pointer;
+               switch (model->type) {
+               case ACPI_TYPE_STRING:
+                       string = model->string.pointer;
+                       break;
+               case ACPI_TYPE_BUFFER:
+                       string = model->buffer.pointer;
+                       break;
+               default:
+                       string = "";
+                       break;
+               }
+       }
+       hotk->name = kstrdup(string, GFP_KERNEL);
+       if (!hotk->name)
+               return -ENOMEM;
+
+       if (*string)
+               printk(ASUS_NOTICE "  %s model detected\n", string);
+
+       ASUS_HANDLE_INIT(mled_set);
+       ASUS_HANDLE_INIT(tled_set);
+       ASUS_HANDLE_INIT(rled_set);
+       ASUS_HANDLE_INIT(pled_set);
+
+       ASUS_HANDLE_INIT(ledd_set);
+
+       /*
+        * The HWRS method return informations about the hardware.
+        * 0x80 bit is for WLAN, 0x100 for Bluetooth.
+        * The significance of others is yet to be found.
+        * If we don't find the method, we assume the device are present.
+        */
+       if (!read_acpi_int(hotk->handle, "HRWS", &hwrs_result, NULL))
+               hwrs_result = WL_HWRS | BT_HWRS;
+
+       if (hwrs_result & WL_HWRS)
+               ASUS_HANDLE_INIT(wl_switch);
+       if (hwrs_result & BT_HWRS)
+               ASUS_HANDLE_INIT(bt_switch);
+
+       ASUS_HANDLE_INIT(wireless_status);
+
+       ASUS_HANDLE_INIT(brightness_set);
+       ASUS_HANDLE_INIT(brightness_get);
+
+       ASUS_HANDLE_INIT(lcd_switch);
+
+       ASUS_HANDLE_INIT(display_set);
+       ASUS_HANDLE_INIT(display_get);
+
+       /* There is a lot of models with "ALSL", but a few get
+          a real light sens, so we need to check it. */
+       if (ASUS_HANDLE_INIT(ls_switch))
+               ASUS_HANDLE_INIT(ls_level);
+
+       kfree(model);
+
+       return AE_OK;
+}
+
+static int asus_hotk_check(void)
+{
+       int result = 0;
+
+       result = acpi_bus_get_status(hotk->device);
+       if (result)
+               return result;
+
+       if (hotk->device->status.present) {
+               result = asus_hotk_get_info();
+       } else {
+               printk(ASUS_ERR "Hotkey device not present, aborting\n");
+               return -EINVAL;
+       }
+
+       return result;
+}
+
+static int asus_hotk_found;
+
+static int asus_hotk_add(struct acpi_device *device)
+{
+       acpi_status status = AE_OK;
+       int result;
+
+       if (!device)
+               return -EINVAL;
+
+       printk(ASUS_NOTICE "Asus Laptop Support version %s\n",
+              ASUS_LAPTOP_VERSION);
+
+       hotk = kmalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+       if (!hotk)
+               return -ENOMEM;
+       memset(hotk, 0, sizeof(struct asus_hotk));
+
+       hotk->handle = device->handle;
+       strcpy(acpi_device_name(device), ASUS_HOTK_DEVICE_NAME);
+       strcpy(acpi_device_class(device), ASUS_HOTK_CLASS);
+       acpi_driver_data(device) = hotk;
+       hotk->device = device;
+
+       result = asus_hotk_check();
+       if (result)
+               goto end;
+
+       asus_hotk_add_fs();
+
+       /*
+        * We install the handler, it will receive the hotk in parameter, so, we
+        * could add other data to the hotk struct
+        */
+       status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+                                            asus_hotk_notify, hotk);
+       if (ACPI_FAILURE(status))
+               printk(ASUS_ERR "Error installing notify handler\n");
+
+       asus_hotk_found = 1;
+
+       /* WLED and BLED are on by default */
+       write_status(bt_switch_handle, 1, BT_ON, 0);
+       write_status(wl_switch_handle, 1, WL_ON, 0);
+
+       /* LCD Backlight is on by default */
+       write_status(NULL, 1, LCD_ON, 0);
+
+       /* LED display is off by default */
+       hotk->ledd_status = 0xFFF;
+
+       /* Set initial values of light sensor and level */
+       hotk->light_switch = 1; /* Default to light sensor disabled */
+       hotk->light_level = 0;  /* level 5 for sensor sensitivity */
+
+       if (ls_switch_handle)
+               set_light_sens_switch(hotk->light_switch);
+
+       if (ls_level_handle)
+               set_light_sens_level(hotk->light_level);
+
+      end:
+       if (result) {
+               kfree(hotk->name);
+               kfree(hotk);
+       }
+
+       return result;
+}
+
+static int asus_hotk_remove(struct acpi_device *device, int type)
+{
+       acpi_status status = 0;
+
+       if (!device || !acpi_driver_data(device))
+               return -EINVAL;
+
+       status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+                                           asus_hotk_notify);
+       if (ACPI_FAILURE(status))
+               printk(ASUS_ERR "Error removing notify handler\n");
+
+       kfree(hotk->name);
+       kfree(hotk);
+
+       return 0;
+}
+
+static void asus_backlight_exit(void)
+{
+       if (asus_backlight_device)
+               backlight_device_unregister(asus_backlight_device);
+}
+
+#define  ASUS_LED_UNREGISTER(object)                           \
+       if(object##_led.class_dev                               \
+          && !IS_ERR(object##_led.class_dev))                  \
+               led_classdev_unregister(&object##_led)
+
+static void asus_led_exit(void)
+{
+       ASUS_LED_UNREGISTER(mled);
+       ASUS_LED_UNREGISTER(tled);
+       ASUS_LED_UNREGISTER(pled);
+       ASUS_LED_UNREGISTER(rled);
+
+       destroy_workqueue(led_workqueue);
+}
+
+static void __exit asus_laptop_exit(void)
+{
+       asus_backlight_exit();
+       asus_led_exit();
+
+       acpi_bus_unregister_driver(&asus_hotk_driver);
+       sysfs_remove_group(&asuspf_device->dev.kobj, &asuspf_attribute_group);
+       platform_device_unregister(asuspf_device);
+       platform_driver_unregister(&asuspf_driver);
+}
+
+static int asus_backlight_init(struct device *dev)
+{
+       struct backlight_device *bd;
+
+       if (brightness_set_handle && lcd_switch_handle) {
+               bd = backlight_device_register(ASUS_HOTK_FILE, dev,
+                                              NULL, &asusbl_data);
+               if (IS_ERR(bd)) {
+                       printk(ASUS_ERR
+                              "Could not register asus backlight device\n");
+                       asus_backlight_device = NULL;
+                       return PTR_ERR(bd);
+               }
+
+               asus_backlight_device = bd;
+
+               down(&bd->sem);
+               if (likely(bd->props)) {
+                       bd->props->brightness = read_brightness(NULL);
+                       bd->props->power = FB_BLANK_UNBLANK;
+                       if (likely(bd->props->update_status))
+                               bd->props->update_status(bd);
+               }
+               up(&bd->sem);
+       }
+       return 0;
+}
+
+static int asus_led_register(acpi_handle handle,
+                            struct led_classdev *ldev, struct device *dev)
+{
+       if (!handle)
+               return 0;
+
+       return led_classdev_register(dev, ldev);
+}
+
+#define ASUS_LED_REGISTER(object, device)                              \
+       asus_led_register(object##_set_handle, &object##_led, device)
+
+static int asus_led_init(struct device *dev)
+{
+       int rv;
+
+       rv = ASUS_LED_REGISTER(mled, dev);
+       if (rv)
+               return rv;
+
+       rv = ASUS_LED_REGISTER(tled, dev);
+       if (rv)
+               return rv;
+
+       rv = ASUS_LED_REGISTER(rled, dev);
+       if (rv)
+               return rv;
+
+       rv = ASUS_LED_REGISTER(pled, dev);
+       if (rv)
+               return rv;
+
+       led_workqueue = create_singlethread_workqueue("led_workqueue");
+       if (!led_workqueue)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static int __init asus_laptop_init(void)
+{
+       struct device *dev;
+       int result;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       if (!acpi_specific_hotkey_enabled) {
+               printk(ASUS_ERR "Using generic hotkey driver\n");
+               return -ENODEV;
+       }
+
+       result = acpi_bus_register_driver(&asus_hotk_driver);
+       if (result < 0)
+               return result;
+
+       /*
+        * This is a bit of a kludge.  We only want this module loaded
+        * for ASUS systems, but there's currently no way to probe the
+        * ACPI namespace for ASUS HIDs.  So we just return failure if
+        * we didn't find one, which will cause the module to be
+        * unloaded.
+        */
+       if (!asus_hotk_found) {
+               acpi_bus_unregister_driver(&asus_hotk_driver);
+               return -ENODEV;
+       }
+
+       dev = acpi_get_physical_device(hotk->device->handle);
+
+       result = asus_backlight_init(dev);
+       if (result)
+               goto fail_backlight;
+
+       result = asus_led_init(dev);
+       if (result)
+               goto fail_led;
+
+       /* Register platform stuff */
+       result = platform_driver_register(&asuspf_driver);
+       if (result)
+               goto fail_platform_driver;
+
+       asuspf_device = platform_device_alloc(ASUS_HOTK_FILE, -1);
+       if (!asuspf_device) {
+               result = -ENOMEM;
+               goto fail_platform_device1;
+       }
+
+       result = platform_device_add(asuspf_device);
+       if (result)
+               goto fail_platform_device2;
+
+       result = sysfs_create_group(&asuspf_device->dev.kobj,
+                                   &asuspf_attribute_group);
+       if (result)
+               goto fail_sysfs;
+
+       return 0;
+
+      fail_sysfs:
+       platform_device_del(asuspf_device);
+
+      fail_platform_device2:
+       platform_device_put(asuspf_device);
+
+      fail_platform_device1:
+       platform_driver_unregister(&asuspf_driver);
+
+      fail_platform_driver:
+       asus_led_exit();
+
+      fail_led:
+       asus_backlight_exit();
+
+      fail_backlight:
+
+       return result;
+}
+
+module_init(asus_laptop_init);
+module_exit(asus_laptop_exit);
index 2ab7add..e21e490 100644 (file)
 
 #include <linux/tifm.h>
 #include <linux/dma-mapping.h>
+#include <linux/freezer.h>
 
 #define DRIVER_NAME "tifm_7xx1"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
 
 static void tifm_7xx1_eject(struct tifm_adapter *fm, struct tifm_dev *sock)
 {
-       int cnt;
-       unsigned long flags;
-
-       spin_lock_irqsave(&fm->lock, flags);
-       if (!fm->inhibit_new_cards) {
-               for (cnt = 0; cnt < fm->max_sockets; cnt++) {
-                       if (fm->sockets[cnt] == sock) {
-                               fm->remove_mask |= (1 << cnt);
-                               queue_work(fm->wq, &fm->media_remover);
-                               break;
-                       }
-               }
-       }
-       spin_unlock_irqrestore(&fm->lock, flags);
-}
-
-static void tifm_7xx1_remove_media(struct work_struct *work)
-{
-       struct tifm_adapter *fm =
-               container_of(work, struct tifm_adapter, media_remover);
        unsigned long flags;
-       int cnt;
-       struct tifm_dev *sock;
 
-       if (!class_device_get(&fm->cdev))
-               return;
        spin_lock_irqsave(&fm->lock, flags);
-       for (cnt = 0; cnt < fm->max_sockets; cnt++) {
-               if (fm->sockets[cnt] && (fm->remove_mask & (1 << cnt))) {
-                       printk(KERN_INFO DRIVER_NAME
-                              ": demand removing card from socket %d\n", cnt);
-                       sock = fm->sockets[cnt];
-                       fm->sockets[cnt] = NULL;
-                       fm->remove_mask &= ~(1 << cnt);
-
-                       writel(0x0e00, sock->addr + SOCK_CONTROL);
-
-                       writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
-                               fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-                       writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
-                               fm->addr + FM_SET_INTERRUPT_ENABLE);
-
-                       spin_unlock_irqrestore(&fm->lock, flags);
-                       device_unregister(&sock->dev);
-                       spin_lock_irqsave(&fm->lock, flags);
-               }
-       }
+       fm->socket_change_set |= 1 << sock->socket_id;
+       wake_up_all(&fm->change_set_notify);
        spin_unlock_irqrestore(&fm->lock, flags);
-       class_device_put(&fm->cdev);
 }
 
 static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
 {
        struct tifm_adapter *fm = dev_id;
+       struct tifm_dev *sock;
        unsigned int irq_status;
        unsigned int sock_irq_status, cnt;
 
@@ -84,42 +43,32 @@ static irqreturn_t tifm_7xx1_isr(int irq, void *dev_id)
        if (irq_status & TIFM_IRQ_ENABLE) {
                writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
 
-               for (cnt = 0; cnt <  fm->max_sockets; cnt++) {
-                       sock_irq_status = (irq_status >> cnt) &
-                                       (TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK);
-
-                       if (fm->sockets[cnt]) {
-                               if (sock_irq_status &&
-                                               fm->sockets[cnt]->signal_irq)
-                                       sock_irq_status = fm->sockets[cnt]->
-                                               signal_irq(fm->sockets[cnt],
-                                                       sock_irq_status);
+               for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+                       sock = fm->sockets[cnt];
+                       sock_irq_status = (irq_status >> cnt)
+                                         & (TIFM_IRQ_FIFOMASK(1)
+                                            | TIFM_IRQ_CARDMASK(1));
 
-                               if (irq_status & (1 << cnt))
-                                       fm->remove_mask |= 1 << cnt;
-                       } else {
-                               if (irq_status & (1 << cnt))
-                                       fm->insert_mask |= 1 << cnt;
-                       }
+                       if (sock && sock_irq_status)
+                               sock->signal_irq(sock, sock_irq_status);
                }
+
+               fm->socket_change_set |= irq_status
+                                        & ((1 << fm->num_sockets) - 1);
        }
        writel(irq_status, fm->addr + FM_INTERRUPT_STATUS);
 
-       if (!fm->inhibit_new_cards) {
-               if (!fm->remove_mask && !fm->insert_mask) {
-                       writel(TIFM_IRQ_ENABLE,
-                               fm->addr + FM_SET_INTERRUPT_ENABLE);
-               } else {
-                       queue_work(fm->wq, &fm->media_remover);
-                       queue_work(fm->wq, &fm->media_inserter);
-               }
-       }
+       if (!fm->socket_change_set)
+               writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
+       else
+               wake_up_all(&fm->change_set_notify);
 
        spin_unlock(&fm->lock);
        return IRQ_HANDLED;
 }
 
-static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is_x2)
+static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr,
+                                                int is_x2)
 {
        unsigned int s_state;
        int cnt;
@@ -127,8 +76,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is
        writel(0x0e00, sock_addr + SOCK_CONTROL);
 
        for (cnt = 0; cnt < 100; cnt++) {
-               if (!(TIFM_SOCK_STATE_POWERED &
-                               readl(sock_addr + SOCK_PRESENT_STATE)))
+               if (!(TIFM_SOCK_STATE_POWERED
+                     & readl(sock_addr + SOCK_PRESENT_STATE)))
                        break;
                msleep(10);
        }
@@ -151,8 +100,8 @@ static tifm_media_id tifm_7xx1_toggle_sock_power(char __iomem *sock_addr, int is
        }
 
        for (cnt = 0; cnt < 100; cnt++) {
-               if ((TIFM_SOCK_STATE_POWERED &
-                               readl(sock_addr + SOCK_PRESENT_STATE)))
+               if ((TIFM_SOCK_STATE_POWERED
+                    & readl(sock_addr + SOCK_PRESENT_STATE)))
                        break;
                msleep(10);
        }
@@ -170,130 +119,209 @@ tifm_7xx1_sock_addr(char __iomem *base_addr, unsigned int sock_num)
        return base_addr + ((sock_num + 1) << 10);
 }
 
-static void tifm_7xx1_insert_media(struct work_struct *work)
+static int tifm_7xx1_switch_media(void *data)
 {
-       struct tifm_adapter *fm =
-               container_of(work, struct tifm_adapter, media_inserter);
+       struct tifm_adapter *fm = data;
        unsigned long flags;
        tifm_media_id media_id;
        char *card_name = "xx";
-       int cnt, ok_to_register;
-       unsigned int insert_mask;
-       struct tifm_dev *new_sock = NULL;
+       int cnt, rc;
+       struct tifm_dev *sock;
+       unsigned int socket_change_set;
 
-       if (!class_device_get(&fm->cdev))
-               return;
-       spin_lock_irqsave(&fm->lock, flags);
-       insert_mask = fm->insert_mask;
-       fm->insert_mask = 0;
-       if (fm->inhibit_new_cards) {
+       while (1) {
+               rc = wait_event_interruptible(fm->change_set_notify,
+                                             fm->socket_change_set);
+               if (rc == -ERESTARTSYS)
+                       try_to_freeze();
+
+               spin_lock_irqsave(&fm->lock, flags);
+               socket_change_set = fm->socket_change_set;
+               fm->socket_change_set = 0;
+
+               dev_dbg(fm->dev, "checking media set %x\n",
+                       socket_change_set);
+
+               if (kthread_should_stop())
+                       socket_change_set = (1 << fm->num_sockets) - 1;
                spin_unlock_irqrestore(&fm->lock, flags);
-               class_device_put(&fm->cdev);
-               return;
-       }
-       spin_unlock_irqrestore(&fm->lock, flags);
 
-       for (cnt = 0; cnt < fm->max_sockets; cnt++) {
-               if (!(insert_mask & (1 << cnt)))
+               if (!socket_change_set)
                        continue;
 
-               media_id = tifm_7xx1_toggle_sock_power(tifm_7xx1_sock_addr(fm->addr, cnt),
-                                                      fm->max_sockets == 2);
-               if (media_id) {
-                       ok_to_register = 0;
-                       new_sock = tifm_alloc_device(fm, cnt);
-                       if (new_sock) {
-                               new_sock->addr = tifm_7xx1_sock_addr(fm->addr,
-                                                                       cnt);
-                               new_sock->media_id = media_id;
-                               switch (media_id) {
-                               case 1:
-                                       card_name = "xd";
-                                       break;
-                               case 2:
-                                       card_name = "ms";
-                                       break;
-                               case 3:
-                                       card_name = "sd";
-                                       break;
-                               default:
-                                       break;
-                               }
-                               snprintf(new_sock->dev.bus_id, BUS_ID_SIZE,
-                                       "tifm_%s%u:%u", card_name, fm->id, cnt);
+               spin_lock_irqsave(&fm->lock, flags);
+               for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+                       if (!(socket_change_set & (1 << cnt)))
+                               continue;
+                       sock = fm->sockets[cnt];
+                       if (sock) {
                                printk(KERN_INFO DRIVER_NAME
-                                       ": %s card detected in socket %d\n",
-                                       card_name, cnt);
+                                      ": demand removing card from socket %d\n",
+                                      cnt);
+                               fm->sockets[cnt] = NULL;
+                               spin_unlock_irqrestore(&fm->lock, flags);
+                               device_unregister(&sock->dev);
                                spin_lock_irqsave(&fm->lock, flags);
-                               if (!fm->sockets[cnt]) {
-                                       fm->sockets[cnt] = new_sock;
-                                       ok_to_register = 1;
+                               writel(0x0e00,
+                                      tifm_7xx1_sock_addr(fm->addr, cnt)
+                                      + SOCK_CONTROL);
+                       }
+                       if (kthread_should_stop())
+                               continue;
+
+                       spin_unlock_irqrestore(&fm->lock, flags);
+                       media_id = tifm_7xx1_toggle_sock_power(
+                                       tifm_7xx1_sock_addr(fm->addr, cnt),
+                                       fm->num_sockets == 2);
+                       if (media_id) {
+                               sock = tifm_alloc_device(fm);
+                               if (sock) {
+                                       sock->addr = tifm_7xx1_sock_addr(fm->addr,
+                                                                        cnt);
+                                       sock->media_id = media_id;
+                                       sock->socket_id = cnt;
+                                       switch (media_id) {
+                                       case 1:
+                                               card_name = "xd";
+                                               break;
+                                       case 2:
+                                               card_name = "ms";
+                                               break;
+                                       case 3:
+                                               card_name = "sd";
+                                               break;
+                                       default:
+                                               tifm_free_device(&sock->dev);
+                                               spin_lock_irqsave(&fm->lock, flags);
+                                               continue;
+                                       }
+                                       snprintf(sock->dev.bus_id, BUS_ID_SIZE,
+                                                "tifm_%s%u:%u", card_name,
+                                                fm->id, cnt);
+                                       printk(KERN_INFO DRIVER_NAME
+                                              ": %s card detected in socket %d\n",
+                                              card_name, cnt);
+                                       if (!device_register(&sock->dev)) {
+                                               spin_lock_irqsave(&fm->lock, flags);
+                                               if (!fm->sockets[cnt]) {
+                                                       fm->sockets[cnt] = sock;
+                                                       sock = NULL;
+                                               }
+                                               spin_unlock_irqrestore(&fm->lock, flags);
+                                       }
+                                       if (sock)
+                                               tifm_free_device(&sock->dev);
                                }
+                               spin_lock_irqsave(&fm->lock, flags);
+                       }
+               }
+
+               if (!kthread_should_stop()) {
+                       writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+                              | TIFM_IRQ_CARDMASK(socket_change_set),
+                              fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+                       writel(TIFM_IRQ_FIFOMASK(socket_change_set)
+                              | TIFM_IRQ_CARDMASK(socket_change_set),
+                              fm->addr + FM_SET_INTERRUPT_ENABLE);
+                       writel(TIFM_IRQ_ENABLE,
+                              fm->addr + FM_SET_INTERRUPT_ENABLE);
+                       spin_unlock_irqrestore(&fm->lock, flags);
+               } else {
+                       for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+                               if (fm->sockets[cnt])
+                                       fm->socket_change_set |= 1 << cnt;
+                       }
+                       if (!fm->socket_change_set) {
+                               spin_unlock_irqrestore(&fm->lock, flags);
+                               return 0;
+                       } else {
                                spin_unlock_irqrestore(&fm->lock, flags);
-                               if (!ok_to_register ||
-                                           device_register(&new_sock->dev)) {
-                                       spin_lock_irqsave(&fm->lock, flags);
-                                       fm->sockets[cnt] = NULL;
-                                       spin_unlock_irqrestore(&fm->lock,
-                                                               flags);
-                                       tifm_free_device(&new_sock->dev);
-                               }
                        }
                }
-               writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
-                      fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-               writel((TIFM_IRQ_FIFOMASK | TIFM_IRQ_CARDMASK) << cnt,
-                      fm->addr + FM_SET_INTERRUPT_ENABLE);
        }
-
-       writel(TIFM_IRQ_ENABLE, fm->addr + FM_SET_INTERRUPT_ENABLE);
-       class_device_put(&fm->cdev);
+       return 0;
 }
 
+#ifdef CONFIG_PM
+
 static int tifm_7xx1_suspend(struct pci_dev *dev, pm_message_t state)
 {
-       struct tifm_adapter *fm = pci_get_drvdata(dev);
-       unsigned long flags;
+       dev_dbg(&dev->dev, "suspending host\n");
 
-       spin_lock_irqsave(&fm->lock, flags);
-       fm->inhibit_new_cards = 1;
-       fm->remove_mask = 0xf;
-       fm->insert_mask = 0;
-       writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-       spin_unlock_irqrestore(&fm->lock, flags);
-       flush_workqueue(fm->wq);
-
-       tifm_7xx1_remove_media(&fm->media_remover);
-
-       pci_set_power_state(dev, PCI_D3hot);
-        pci_disable_device(dev);
-        pci_save_state(dev);
+       pci_save_state(dev);
+       pci_enable_wake(dev, pci_choose_state(dev, state), 0);
+       pci_disable_device(dev);
+       pci_set_power_state(dev, pci_choose_state(dev, state));
        return 0;
 }
 
 static int tifm_7xx1_resume(struct pci_dev *dev)
 {
        struct tifm_adapter *fm = pci_get_drvdata(dev);
+       int cnt, rc;
        unsigned long flags;
+       tifm_media_id new_ids[fm->num_sockets];
 
+       pci_set_power_state(dev, PCI_D0);
        pci_restore_state(dev);
-        pci_enable_device(dev);
-        pci_set_power_state(dev, PCI_D0);
-        pci_set_master(dev);
+       rc = pci_enable_device(dev);
+       if (rc)
+               return rc;
+       pci_set_master(dev);
 
+       dev_dbg(&dev->dev, "resuming host\n");
+
+       for (cnt = 0; cnt < fm->num_sockets; cnt++)
+               new_ids[cnt] = tifm_7xx1_toggle_sock_power(
+                                       tifm_7xx1_sock_addr(fm->addr, cnt),
+                                       fm->num_sockets == 2);
        spin_lock_irqsave(&fm->lock, flags);
-       fm->inhibit_new_cards = 0;
-       writel(TIFM_IRQ_SETALL, fm->addr + FM_INTERRUPT_STATUS);
-       writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-       writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
-               fm->addr + FM_SET_INTERRUPT_ENABLE);
-       fm->insert_mask = 0xf;
+       fm->socket_change_set = 0;
+       for (cnt = 0; cnt < fm->num_sockets; cnt++) {
+               if (fm->sockets[cnt]) {
+                       if (fm->sockets[cnt]->media_id == new_ids[cnt])
+                               fm->socket_change_set |= 1 << cnt;
+
+                       fm->sockets[cnt]->media_id = new_ids[cnt];
+               }
+       }
+
+       writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
+              fm->addr + FM_SET_INTERRUPT_ENABLE);
+       if (!fm->socket_change_set) {
+               spin_unlock_irqrestore(&fm->lock, flags);
+               return 0;
+       } else {
+               fm->socket_change_set = 0;
+               spin_unlock_irqrestore(&fm->lock, flags);
+       }
+
+       wait_event_timeout(fm->change_set_notify, fm->socket_change_set, HZ);
+
+       spin_lock_irqsave(&fm->lock, flags);
+       writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
+              | TIFM_IRQ_CARDMASK(fm->socket_change_set),
+              fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+       writel(TIFM_IRQ_FIFOMASK(fm->socket_change_set)
+              | TIFM_IRQ_CARDMASK(fm->socket_change_set),
+              fm->addr + FM_SET_INTERRUPT_ENABLE);
+       writel(TIFM_IRQ_ENABLE,
+              fm->addr + FM_SET_INTERRUPT_ENABLE);
+       fm->socket_change_set = 0;
+
        spin_unlock_irqrestore(&fm->lock, flags);
        return 0;
 }
 
+#else
+
+#define tifm_7xx1_suspend NULL
+#define tifm_7xx1_resume NULL
+
+#endif /* CONFIG_PM */
+
 static int tifm_7xx1_probe(struct pci_dev *dev,
-                       const struct pci_device_id *dev_id)
+                          const struct pci_device_id *dev_id)
 {
        struct tifm_adapter *fm;
        int pci_dev_busy = 0;
@@ -324,19 +352,18 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
        }
 
        fm->dev = &dev->dev;
-       fm->max_sockets = (dev->device == 0x803B) ? 2 : 4;
-       fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->max_sockets,
-                               GFP_KERNEL);
+       fm->num_sockets = (dev->device == PCI_DEVICE_ID_TI_XX21_XX11_FM)
+                         ? 4 : 2;
+       fm->sockets = kzalloc(sizeof(struct tifm_dev*) * fm->num_sockets,
+                             GFP_KERNEL);
        if (!fm->sockets)
                goto err_out_free;
 
-       INIT_WORK(&fm->media_inserter, tifm_7xx1_insert_media);
-       INIT_WORK(&fm->media_remover, tifm_7xx1_remove_media);
        fm->eject = tifm_7xx1_eject;
        pci_set_drvdata(dev, fm);
 
        fm->addr = ioremap(pci_resource_start(dev, 0),
-                               pci_resource_len(dev, 0));
+                          pci_resource_len(dev, 0));
        if (!fm->addr)
                goto err_out_free;
 
@@ -344,16 +371,15 @@ static int tifm_7xx1_probe(struct pci_dev *dev,
        if (rc)
                goto err_out_unmap;
 
-       rc = tifm_add_adapter(fm);
+       init_waitqueue_head(&fm->change_set_notify);
+       rc = tifm_add_adapter(fm, tifm_7xx1_switch_media);
        if (rc)
                goto err_out_irq;
 
        writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-       writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SETALLSOCK,
-               fm->addr + FM_SET_INTERRUPT_ENABLE);
-
-       fm->insert_mask = 0xf;
-
+       writel(TIFM_IRQ_ENABLE | TIFM_IRQ_SOCKMASK((1 << fm->num_sockets) - 1),
+              fm->addr + FM_SET_INTERRUPT_ENABLE);
+       wake_up_process(fm->media_switcher);
        return 0;
 
 err_out_irq:
@@ -377,19 +403,15 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
        struct tifm_adapter *fm = pci_get_drvdata(dev);
        unsigned long flags;
 
+       writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+       mmiowb();
+       free_irq(dev->irq, fm);
+
        spin_lock_irqsave(&fm->lock, flags);
-       fm->inhibit_new_cards = 1;
-       fm->remove_mask = 0xf;
-       fm->insert_mask = 0;
-       writel(TIFM_IRQ_ENABLE, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
+       fm->socket_change_set = (1 << fm->num_sockets) - 1;
        spin_unlock_irqrestore(&fm->lock, flags);
 
-       flush_workqueue(fm->wq);
-
-       tifm_7xx1_remove_media(&fm->media_remover);
-
-       writel(TIFM_IRQ_SETALL, fm->addr + FM_CLEAR_INTERRUPT_ENABLE);
-       free_irq(dev->irq, fm);
+       kthread_stop(fm->media_switcher);
 
        tifm_remove_adapter(fm);
 
@@ -404,10 +426,12 @@ static void tifm_7xx1_remove(struct pci_dev *dev)
 }
 
 static struct pci_device_id tifm_7xx1_pci_tbl [] = {
-       { PCI_VENDOR_ID_TI, 0x8033, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         0 }, /* xx21 - the one I have */
-        { PCI_VENDOR_ID_TI, 0x803B, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         0 }, /* xx12 - should be also supported */
+       { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX21_XX11_FM, PCI_ANY_ID,
+         PCI_ANY_ID, 0, 0, 0 }, /* xx21 - the one I have */
+        { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX12_FM, PCI_ANY_ID,
+         PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_XX20_FM, PCI_ANY_ID,
+         PCI_ANY_ID, 0, 0, 0 },
        { }
 };
 
index d61df5c..6b10ebe 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/idr.h>
 
 #define DRIVER_NAME "tifm_core"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
 
 static DEFINE_IDR(tifm_adapter_idr);
 static DEFINE_SPINLOCK(tifm_adapter_lock);
@@ -60,10 +60,41 @@ static int tifm_uevent(struct device *dev, char **envp, int num_envp,
        return 0;
 }
 
+#ifdef CONFIG_PM
+
+static int tifm_device_suspend(struct device *dev, pm_message_t state)
+{
+       struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+       struct tifm_driver *drv = fm_dev->drv;
+
+       if (drv && drv->suspend)
+               return drv->suspend(fm_dev, state);
+       return 0;
+}
+
+static int tifm_device_resume(struct device *dev)
+{
+       struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
+       struct tifm_driver *drv = fm_dev->drv;
+
+       if (drv && drv->resume)
+               return drv->resume(fm_dev);
+       return 0;
+}
+
+#else
+
+#define tifm_device_suspend NULL
+#define tifm_device_resume NULL
+
+#endif /* CONFIG_PM */
+
 static struct bus_type tifm_bus_type = {
        .name    = "tifm",
        .match   = tifm_match,
        .uevent  = tifm_uevent,
+       .suspend = tifm_device_suspend,
+       .resume  = tifm_device_resume
 };
 
 static void tifm_free(struct class_device *cdev)
@@ -71,8 +102,6 @@ static void tifm_free(struct class_device *cdev)
        struct tifm_adapter *fm = container_of(cdev, struct tifm_adapter, cdev);
 
        kfree(fm->sockets);
-       if (fm->wq)
-               destroy_workqueue(fm->wq);
        kfree(fm);
 }
 
@@ -101,7 +130,8 @@ void tifm_free_adapter(struct tifm_adapter *fm)
 }
 EXPORT_SYMBOL(tifm_free_adapter);
 
-int tifm_add_adapter(struct tifm_adapter *fm)
+int tifm_add_adapter(struct tifm_adapter *fm,
+                    int (*mediathreadfn)(void *data))
 {
        int rc;
 
@@ -113,10 +143,10 @@ int tifm_add_adapter(struct tifm_adapter *fm)
        spin_unlock(&tifm_adapter_lock);
        if (!rc) {
                snprintf(fm->cdev.class_id, BUS_ID_SIZE, "tifm%u", fm->id);
-               strncpy(fm->wq_name, fm->cdev.class_id, KOBJ_NAME_LEN);
+               fm->media_switcher = kthread_create(mediathreadfn,
+                                                   fm, "tifm/%u", fm->id);
 
-               fm->wq = create_singlethread_workqueue(fm->wq_name);
-               if (fm->wq)
+               if (!IS_ERR(fm->media_switcher))
                        return class_device_add(&fm->cdev);
 
                spin_lock(&tifm_adapter_lock);
@@ -141,27 +171,27 @@ EXPORT_SYMBOL(tifm_remove_adapter);
 void tifm_free_device(struct device *dev)
 {
        struct tifm_dev *fm_dev = container_of(dev, struct tifm_dev, dev);
-       if (fm_dev->wq)
-               destroy_workqueue(fm_dev->wq);
        kfree(fm_dev);
 }
 EXPORT_SYMBOL(tifm_free_device);
 
-struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id)
+static void tifm_dummy_signal_irq(struct tifm_dev *sock,
+                                 unsigned int sock_irq_status)
+{
+       return;
+}
+
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm)
 {
        struct tifm_dev *dev = kzalloc(sizeof(struct tifm_dev), GFP_KERNEL);
 
        if (dev) {
                spin_lock_init(&dev->lock);
-               snprintf(dev->wq_name, KOBJ_NAME_LEN, "tifm%u:%u", fm->id, id);
-               dev->wq = create_singlethread_workqueue(dev->wq_name);
-               if (!dev->wq) {
-                       kfree(dev);
-                       return NULL;
-               }
+
                dev->dev.parent = fm->dev;
                dev->dev.bus = &tifm_bus_type;
                dev->dev.release = tifm_free_device;
+               dev->signal_irq = tifm_dummy_signal_irq;
        }
        return dev;
 }
@@ -219,6 +249,7 @@ static int tifm_device_remove(struct device *dev)
        struct tifm_driver *drv = fm_dev->drv;
 
        if (drv) {
+               fm_dev->signal_irq = tifm_dummy_signal_irq;
                if (drv->remove)
                        drv->remove(fm_dev);
                fm_dev->drv = NULL;
@@ -233,6 +264,8 @@ int tifm_register_driver(struct tifm_driver *drv)
        drv->driver.bus = &tifm_bus_type;
        drv->driver.probe = tifm_device_probe;
        drv->driver.remove = tifm_device_remove;
+       drv->driver.suspend = tifm_device_suspend;
+       drv->driver.resume = tifm_device_resume;
 
        return driver_register(&drv->driver);
 }
index aa152f3..2ce50f3 100644 (file)
@@ -823,6 +823,9 @@ static int __init at91_mci_probe(struct platform_device *pdev)
        mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
        mmc->caps = MMC_CAP_BYTEBLOCK;
 
+       mmc->max_blk_size = 4095;
+       mmc->max_blk_count = mmc->max_req_size;
+
        host = mmc_priv(mmc);
        host->mmc = mmc;
        host->buffer = NULL;
index 800527c..b834be2 100644 (file)
@@ -152,8 +152,9 @@ static inline int au1xmmc_card_inserted(struct au1xmmc_host *host)
                ? 1 : 0;
 }
 
-static inline int au1xmmc_card_readonly(struct au1xmmc_host *host)
+static int au1xmmc_card_readonly(struct mmc_host *mmc)
 {
+       struct au1xmmc_host *host = mmc_priv(mmc);
        return (bcsr->status & au1xmmc_card_table[host->id].wpstatus)
                ? 1 : 0;
 }
@@ -193,6 +194,8 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
        u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
 
        switch (mmc_resp_type(cmd)) {
+       case MMC_RSP_NONE:
+               break;
        case MMC_RSP_R1:
                mmccmd |= SD_CMD_RT_1;
                break;
@@ -205,6 +208,10 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
        case MMC_RSP_R3:
                mmccmd |= SD_CMD_RT_3;
                break;
+       default:
+               printk(KERN_INFO "au1xmmc: unhandled response type %02x\n",
+                       mmc_resp_type(cmd));
+               return MMC_ERR_INVALID;
        }
 
        switch(cmd->opcode) {
@@ -878,6 +885,7 @@ static void au1xmmc_init_dma(struct au1xmmc_host *host)
 static const struct mmc_host_ops au1xmmc_ops = {
        .request        = au1xmmc_request,
        .set_ios        = au1xmmc_set_ios,
+       .get_ro         = au1xmmc_card_readonly,
 };
 
 static int __devinit au1xmmc_probe(struct platform_device *pdev)
@@ -914,6 +922,9 @@ static int __devinit au1xmmc_probe(struct platform_device *pdev)
                mmc->max_seg_size = AU1XMMC_DESCRIPTOR_SIZE;
                mmc->max_phys_segs = AU1XMMC_DESCRIPTOR_COUNT;
 
+               mmc->max_blk_size = 2048;
+               mmc->max_blk_count = 512;
+
                mmc->ocr_avail = AU1XMMC_OCR;
 
                host = mmc_priv(mmc);
index bfb9ff6..b060d4b 100644 (file)
@@ -958,8 +958,10 @@ static int imxmci_probe(struct platform_device *pdev)
        /* MMC core transfer sizes tunable parameters */
        mmc->max_hw_segs = 64;
        mmc->max_phys_segs = 64;
-       mmc->max_sectors = 64;          /* default 1 << (PAGE_CACHE_SHIFT - 9) */
        mmc->max_seg_size = 64*512;     /* default PAGE_CACHE_SIZE */
+       mmc->max_req_size = 64*512;     /* default PAGE_CACHE_SIZE */
+       mmc->max_blk_size = 2048;
+       mmc->max_blk_count = 65535;
 
        host = mmc_priv(mmc);
        host->mmc = mmc;
index 6f2a282..5046a16 100644 (file)
@@ -103,11 +103,16 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
                 mmc_hostname(host), mrq->cmd->opcode,
                 mrq->cmd->arg, mrq->cmd->flags);
 
-       WARN_ON(host->card_busy == NULL);
+       WARN_ON(!host->claimed);
 
        mrq->cmd->error = 0;
        mrq->cmd->mrq = mrq;
        if (mrq->data) {
+               BUG_ON(mrq->data->blksz > host->max_blk_size);
+               BUG_ON(mrq->data->blocks > host->max_blk_count);
+               BUG_ON(mrq->data->blocks * mrq->data->blksz >
+                       host->max_req_size);
+
                mrq->cmd->data = mrq->data;
                mrq->data->error = 0;
                mrq->data->mrq = mrq;
@@ -157,7 +162,7 @@ int mmc_wait_for_cmd(struct mmc_host *host, struct mmc_command *cmd, int retries
 {
        struct mmc_request mrq;
 
-       BUG_ON(host->card_busy == NULL);
+       BUG_ON(!host->claimed);
 
        memset(&mrq, 0, sizeof(struct mmc_request));
 
@@ -195,7 +200,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
 
        int i, err;
 
-       BUG_ON(host->card_busy == NULL);
+       BUG_ON(!host->claimed);
        BUG_ON(retries < 0);
 
        err = MMC_ERR_INVALID;
@@ -289,7 +294,10 @@ void mmc_set_data_timeout(struct mmc_data *data, const struct mmc_card *card,
                else
                        limit_us = 100000;
 
-               if (timeout_us > limit_us) {
+               /*
+                * SDHC cards always use these fixed values.
+                */
+               if (timeout_us > limit_us || mmc_card_blockaddr(card)) {
                        data->timeout_ns = limit_us * 1000;
                        data->timeout_clks = 0;
                }
@@ -320,14 +328,14 @@ int __mmc_claim_host(struct mmc_host *host, struct mmc_card *card)
        spin_lock_irqsave(&host->lock, flags);
        while (1) {
                set_current_state(TASK_UNINTERRUPTIBLE);
-               if (host->card_busy == NULL)
+               if (!host->claimed)
                        break;
                spin_unlock_irqrestore(&host->lock, flags);
                schedule();
                spin_lock_irqsave(&host->lock, flags);
        }
        set_current_state(TASK_RUNNING);
-       host->card_busy = card;
+       host->claimed = 1;
        spin_unlock_irqrestore(&host->lock, flags);
        remove_wait_queue(&host->wq, &wait);
 
@@ -353,10 +361,10 @@ void mmc_release_host(struct mmc_host *host)
 {
        unsigned long flags;
 
-       BUG_ON(host->card_busy == NULL);
+       BUG_ON(!host->claimed);
 
        spin_lock_irqsave(&host->lock, flags);
-       host->card_busy = NULL;
+       host->claimed = 0;
        spin_unlock_irqrestore(&host->lock, flags);
 
        wake_up(&host->wq);
@@ -372,7 +380,7 @@ static inline void mmc_set_ios(struct mmc_host *host)
                 mmc_hostname(host), ios->clock, ios->bus_mode,
                 ios->power_mode, ios->chip_select, ios->vdd,
                 ios->bus_width);
-       
+
        host->ops->set_ios(host, ios);
 }
 
@@ -381,7 +389,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
        int err;
        struct mmc_command cmd;
 
-       BUG_ON(host->card_busy == NULL);
+       BUG_ON(!host->claimed);
 
        if (host->card_selected == card)
                return MMC_ERR_NONE;
@@ -588,34 +596,65 @@ static void mmc_decode_csd(struct mmc_card *card)
 
        if (mmc_card_sd(card)) {
                csd_struct = UNSTUFF_BITS(resp, 126, 2);
-               if (csd_struct != 0) {
+
+               switch (csd_struct) {
+               case 0:
+                       m = UNSTUFF_BITS(resp, 115, 4);
+                       e = UNSTUFF_BITS(resp, 112, 3);
+                       csd->tacc_ns     = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
+                       csd->tacc_clks   = UNSTUFF_BITS(resp, 104, 8) * 100;
+
+                       m = UNSTUFF_BITS(resp, 99, 4);
+                       e = UNSTUFF_BITS(resp, 96, 3);
+                       csd->max_dtr      = tran_exp[e] * tran_mant[m];
+                       csd->cmdclass     = UNSTUFF_BITS(resp, 84, 12);
+
+                       e = UNSTUFF_BITS(resp, 47, 3);
+                       m = UNSTUFF_BITS(resp, 62, 12);
+                       csd->capacity     = (1 + m) << (e + 2);
+
+                       csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
+                       csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
+                       csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
+                       csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
+                       csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
+                       csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
+                       csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
+                       break;
+               case 1:
+                       /*
+                        * This is a block-addressed SDHC card. Most
+                        * interesting fields are unused and have fixed
+                        * values. To avoid getting tripped by buggy cards,
+                        * we assume those fixed values ourselves.
+                        */
+                       mmc_card_set_blockaddr(card);
+
+                       csd->tacc_ns     = 0; /* Unused */
+                       csd->tacc_clks   = 0; /* Unused */
+
+                       m = UNSTUFF_BITS(resp, 99, 4);
+                       e = UNSTUFF_BITS(resp, 96, 3);
+                       csd->max_dtr      = tran_exp[e] * tran_mant[m];
+                       csd->cmdclass     = UNSTUFF_BITS(resp, 84, 12);
+
+                       m = UNSTUFF_BITS(resp, 48, 22);
+                       csd->capacity     = (1 + m) << 10;
+
+                       csd->read_blkbits = 9;
+                       csd->read_partial = 0;
+                       csd->write_misalign = 0;
+                       csd->read_misalign = 0;
+                       csd->r2w_factor = 4; /* Unused */
+                       csd->write_blkbits = 9;
+                       csd->write_partial = 0;
+                       break;
+               default:
                        printk("%s: unrecognised CSD structure version %d\n",
                                mmc_hostname(card->host), csd_struct);
                        mmc_card_set_bad(card);
                        return;
                }
-
-               m = UNSTUFF_BITS(resp, 115, 4);
-               e = UNSTUFF_BITS(resp, 112, 3);
-               csd->tacc_ns     = (tacc_exp[e] * tacc_mant[m] + 9) / 10;
-               csd->tacc_clks   = UNSTUFF_BITS(resp, 104, 8) * 100;
-
-               m = UNSTUFF_BITS(resp, 99, 4);
-               e = UNSTUFF_BITS(resp, 96, 3);
-               csd->max_dtr      = tran_exp[e] * tran_mant[m];
-               csd->cmdclass     = UNSTUFF_BITS(resp, 84, 12);
-
-               e = UNSTUFF_BITS(resp, 47, 3);
-               m = UNSTUFF_BITS(resp, 62, 12);
-               csd->capacity     = (1 + m) << (e + 2);
-
-               csd->read_blkbits = UNSTUFF_BITS(resp, 80, 4);
-               csd->read_partial = UNSTUFF_BITS(resp, 79, 1);
-               csd->write_misalign = UNSTUFF_BITS(resp, 78, 1);
-               csd->read_misalign = UNSTUFF_BITS(resp, 77, 1);
-               csd->r2w_factor = UNSTUFF_BITS(resp, 26, 3);
-               csd->write_blkbits = UNSTUFF_BITS(resp, 22, 4);
-               csd->write_partial = UNSTUFF_BITS(resp, 21, 1);
        } else {
                /*
                 * We only understand CSD structure v1.1 and v1.2.
@@ -848,6 +887,41 @@ static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
        return err;
 }
 
+static int mmc_send_if_cond(struct mmc_host *host, u32 ocr, int *rsd2)
+{
+       struct mmc_command cmd;
+       int err, sd2;
+       static const u8 test_pattern = 0xAA;
+
+       /*
+       * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND
+       * before SD_APP_OP_COND. This command will harmlessly fail for
+       * SD 1.0 cards.
+       */
+       cmd.opcode = SD_SEND_IF_COND;
+       cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern;
+       cmd.flags = MMC_RSP_R7 | MMC_CMD_BCR;
+
+       err = mmc_wait_for_cmd(host, &cmd, 0);
+       if (err == MMC_ERR_NONE) {
+               if ((cmd.resp[0] & 0xFF) == test_pattern) {
+                       sd2 = 1;
+               } else {
+                       sd2 = 0;
+                       err = MMC_ERR_FAILED;
+               }
+       } else {
+               /*
+                * Treat errors as SD 1.0 card.
+                */
+               sd2 = 0;
+               err = MMC_ERR_NONE;
+       }
+       if (rsd2)
+               *rsd2 = sd2;
+       return err;
+}
+
 /*
  * Discover cards by requesting their CID.  If this command
  * times out, it is not an error; there are no further cards
@@ -1018,7 +1092,8 @@ static void mmc_process_ext_csds(struct mmc_host *host)
                mmc_wait_for_req(host, &mrq);
 
                if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
-                       mmc_card_set_dead(card);
+                       printk("%s: unable to read EXT_CSD, performance "
+                               "might suffer.\n", mmc_hostname(card->host));
                        continue;
                }
 
@@ -1034,7 +1109,6 @@ static void mmc_process_ext_csds(struct mmc_host *host)
                        printk("%s: card is mmc v4 but doesn't support "
                               "any high-speed modes.\n",
                                mmc_hostname(card->host));
-                       mmc_card_set_bad(card);
                        continue;
                }
 
@@ -1215,7 +1289,9 @@ static void mmc_read_switch_caps(struct mmc_host *host)
                mmc_wait_for_req(host, &mrq);
 
                if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
-                       mmc_card_set_dead(card);
+                       printk("%s: unable to read switch capabilities, "
+                               "performance might suffer.\n",
+                               mmc_hostname(card->host));
                        continue;
                }
 
@@ -1247,12 +1323,8 @@ static void mmc_read_switch_caps(struct mmc_host *host)
 
                mmc_wait_for_req(host, &mrq);
 
-               if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE) {
-                       mmc_card_set_dead(card);
-                       continue;
-               }
-
-               if ((status[16] & 0xF) != 1) {
+               if (cmd.error != MMC_ERR_NONE || data.error != MMC_ERR_NONE ||
+                       (status[16] & 0xF) != 1) {
                        printk(KERN_WARNING "%s: Problem switching card "
                                "into high-speed mode!\n",
                                mmc_hostname(host));
@@ -1334,6 +1406,10 @@ static void mmc_setup(struct mmc_host *host)
                mmc_power_up(host);
                mmc_idle_cards(host);
 
+               err = mmc_send_if_cond(host, host->ocr_avail, NULL);
+               if (err != MMC_ERR_NONE) {
+                       return;
+               }
                err = mmc_send_app_op_cond(host, 0, &ocr);
 
                /*
@@ -1386,10 +1462,21 @@ static void mmc_setup(struct mmc_host *host)
         * all get the idea that they should be ready for CMD2.
         * (My SanDisk card seems to need this.)
         */
-       if (host->mode == MMC_MODE_SD)
-               mmc_send_app_op_cond(host, host->ocr, NULL);
-       else
+       if (host->mode == MMC_MODE_SD) {
+               int err, sd2;
+               err = mmc_send_if_cond(host, host->ocr, &sd2);
+               if (err == MMC_ERR_NONE) {
+                       /*
+                       * If SD_SEND_IF_COND indicates an SD 2.0
+                       * compliant card and we should set bit 30
+                       * of the ocr to indicate that we can handle
+                       * block-addressed SDHC cards.
+                       */
+                       mmc_send_app_op_cond(host, host->ocr | (sd2 << 30), NULL);
+               }
+       } else {
                mmc_send_op_cond(host, host->ocr, NULL);
+       }
 
        mmc_discover_cards(host);
 
@@ -1519,8 +1606,11 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
                 */
                host->max_hw_segs = 1;
                host->max_phys_segs = 1;
-               host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
                host->max_seg_size = PAGE_CACHE_SIZE;
+
+               host->max_req_size = PAGE_CACHE_SIZE;
+               host->max_blk_size = 512;
+               host->max_blk_count = PAGE_CACHE_SIZE / 512;
        }
 
        return host;
index 8771357..05ba8ac 100644 (file)
@@ -237,13 +237,17 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                brq.mrq.cmd = &brq.cmd;
                brq.mrq.data = &brq.data;
 
-               brq.cmd.arg = req->sector << 9;
+               brq.cmd.arg = req->sector;
+               if (!mmc_card_blockaddr(card))
+                       brq.cmd.arg <<= 9;
                brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
                brq.data.blksz = 1 << md->block_bits;
-               brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
                brq.stop.opcode = MMC_STOP_TRANSMISSION;
                brq.stop.arg = 0;
                brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
+               brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
+               if (brq.data.blocks > card->host->max_blk_count)
+                       brq.data.blocks = card->host->max_blk_count;
 
                mmc_set_data_timeout(&brq.data, card, rq_data_dir(req) != READ);
 
@@ -375,9 +379,10 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
                spin_unlock_irq(&md->lock);
        }
 
+flush_queue:
+
        mmc_card_release_host(card);
 
-flush_queue:
        spin_lock_irq(&md->lock);
        while (ret) {
                ret = end_that_request_chunk(req, 0,
@@ -494,6 +499,10 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
        struct mmc_command cmd;
        int err;
 
+       /* Block-addressed cards ignore MMC_SET_BLOCKLEN. */
+       if (mmc_card_blockaddr(card))
+               return 0;
+
        mmc_card_claim_host(card);
        cmd.opcode = MMC_SET_BLOCKLEN;
        cmd.arg = 1 << md->block_bits;
index 3e35a43..c27e426 100644 (file)
@@ -147,7 +147,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
 
        blk_queue_prep_rq(mq->queue, mmc_prep_request);
        blk_queue_bounce_limit(mq->queue, limit);
-       blk_queue_max_sectors(mq->queue, host->max_sectors);
+       blk_queue_max_sectors(mq->queue, host->max_req_size / 512);
        blk_queue_max_phys_segments(mq->queue, host->max_phys_segs);
        blk_queue_max_hw_segments(mq->queue, host->max_hw_segs);
        blk_queue_max_segment_size(mq->queue, host->max_seg_size);
index e334acd..d32698b 100644 (file)
@@ -199,7 +199,7 @@ void mmc_init_card(struct mmc_card *card, struct mmc_host *host)
        memset(card, 0, sizeof(struct mmc_card));
        card->host = host;
        device_initialize(&card->dev);
-       card->dev.parent = mmc_dev(host);
+       card->dev.parent = mmc_classdev(host);
        card->dev.bus = &mmc_bus_type;
        card->dev.release = mmc_release_card;
 }
index ccfe656..5941dd9 100644 (file)
@@ -524,15 +524,24 @@ static int mmci_probe(struct amba_device *dev, void *id)
        /*
         * Since we only have a 16-bit data length register, we must
         * ensure that we don't exceed 2^16-1 bytes in a single request.
-        * Choose 64 (512-byte) sectors as the limit.
         */
-       mmc->max_sectors = 64;
+       mmc->max_req_size = 65535;
 
        /*
         * Set the maximum segment size.  Since we aren't doing DMA
         * (yet) we are only limited by the data length register.
         */
-       mmc->max_seg_size = mmc->max_sectors << 9;
+       mmc->max_seg_size = mmc->max_req_size;
+
+       /*
+        * Block size can be up to 2048 bytes, but must be a power of two.
+        */
+       mmc->max_blk_size = 2048;
+
+       /*
+        * No limit on the number of blocks transferred.
+        */
+       mmc->max_blk_count = mmc->max_req_size;
 
        spin_lock_init(&host->lock);
 
index d30540b..1e96a2f 100644 (file)
@@ -1099,8 +1099,10 @@ static int __init mmc_omap_probe(struct platform_device *pdev)
         */
        mmc->max_phys_segs = 32;
        mmc->max_hw_segs = 32;
-       mmc->max_sectors = 256; /* NBLK max 11-bits, OMAP also limited by DMA */
-       mmc->max_seg_size = mmc->max_sectors * 512;
+       mmc->max_blk_size = 2048;       /* BLEN is 11 bits (+1) */
+       mmc->max_blk_count = 2048;      /* NBLK is 11 bits (+1) */
+       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+       mmc->max_seg_size = mmc->max_req_size;
 
        if (host->power_pin >= 0) {
                if ((ret = omap_request_gpio(host->power_pin)) != 0) {
index 6073d99..9774fc6 100644 (file)
@@ -450,6 +450,16 @@ static int pxamci_probe(struct platform_device *pdev)
         */
        mmc->max_seg_size = PAGE_SIZE;
 
+       /*
+        * Block length register is 10 bits.
+        */
+       mmc->max_blk_size = 1023;
+
+       /*
+        * Block count register is 16 bits.
+        */
+       mmc->max_blk_count = 65535;
+
        host = mmc_priv(mmc);
        host->mmc = mmc;
        host->dma = -1;
index c2d13d7..4bf1fea 100644 (file)
@@ -37,6 +37,7 @@ static unsigned int debug_quirks = 0;
 #define SDHCI_QUIRK_FORCE_DMA                          (1<<1)
 /* Controller doesn't like some resets when there is no card inserted. */
 #define SDHCI_QUIRK_NO_CARD_NO_RESET                   (1<<2)
+#define SDHCI_QUIRK_SINGLE_POWER_WRITE                 (1<<3)
 
 static const struct pci_device_id pci_ids[] __devinitdata = {
        {
@@ -65,6 +66,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
                .driver_data    = SDHCI_QUIRK_FORCE_DMA,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_ENE,
+               .device         = PCI_DEVICE_ID_ENE_CB712_SD,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE,
+       },
+
        {       /* Generic SD host controller */
                PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
        },
@@ -197,15 +206,9 @@ static void sdhci_deactivate_led(struct sdhci_host *host)
  *                                                                           *
 \*****************************************************************************/
 
-static inline char* sdhci_kmap_sg(struct sdhci_host* host)
+static inline char* sdhci_sg_to_buffer(struct sdhci_host* host)
 {
-       host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ);
-       return host->mapped_sg + host->cur_sg->offset;
-}
-
-static inline void sdhci_kunmap_sg(struct sdhci_host* host)
-{
-       kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+       return page_address(host->cur_sg->page) + host->cur_sg->offset;
 }
 
 static inline int sdhci_next_sg(struct sdhci_host* host)
@@ -240,7 +243,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
        chunk_remain = 0;
        data = 0;
 
-       buffer = sdhci_kmap_sg(host) + host->offset;
+       buffer = sdhci_sg_to_buffer(host) + host->offset;
 
        while (blksize) {
                if (chunk_remain == 0) {
@@ -264,16 +267,13 @@ static void sdhci_read_block_pio(struct sdhci_host *host)
                }
 
                if (host->remain == 0) {
-                       sdhci_kunmap_sg(host);
                        if (sdhci_next_sg(host) == 0) {
                                BUG_ON(blksize != 0);
                                return;
                        }
-                       buffer = sdhci_kmap_sg(host);
+                       buffer = sdhci_sg_to_buffer(host);
                }
        }
-
-       sdhci_kunmap_sg(host);
 }
 
 static void sdhci_write_block_pio(struct sdhci_host *host)
@@ -290,7 +290,7 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
        data = 0;
 
        bytes = 0;
-       buffer = sdhci_kmap_sg(host) + host->offset;
+       buffer = sdhci_sg_to_buffer(host) + host->offset;
 
        while (blksize) {
                size = min(host->size, host->remain);
@@ -314,16 +314,13 @@ static void sdhci_write_block_pio(struct sdhci_host *host)
                }
 
                if (host->remain == 0) {
-                       sdhci_kunmap_sg(host);
                        if (sdhci_next_sg(host) == 0) {
                                BUG_ON(blksize != 0);
                                return;
                        }
-                       buffer = sdhci_kmap_sg(host);
+                       buffer = sdhci_sg_to_buffer(host);
                }
        }
-
-       sdhci_kunmap_sg(host);
 }
 
 static void sdhci_transfer_pio(struct sdhci_host *host)
@@ -372,7 +369,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 
        /* Sanity checks */
        BUG_ON(data->blksz * data->blocks > 524288);
-       BUG_ON(data->blksz > host->max_block);
+       BUG_ON(data->blksz > host->mmc->max_blk_size);
        BUG_ON(data->blocks > 65535);
 
        /* timeout in us */
@@ -674,10 +671,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
        if (host->power == power)
                return;
 
-       writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
-
-       if (power == (unsigned short)-1)
+       if (power == (unsigned short)-1) {
+               writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
                goto out;
+       }
+
+       /*
+        * Spec says that we should clear the power reg before setting
+        * a new value. Some controllers don't seem to like this though.
+        */
+       if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
+               writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
 
        pwr = SDHCI_POWER_ON;
 
@@ -1109,7 +1113,9 @@ static int sdhci_resume (struct pci_dev *pdev)
 
        pci_set_power_state(pdev, PCI_D0);
        pci_restore_state(pdev);
-       pci_enable_device(pdev);
+       ret = pci_enable_device(pdev);
+       if (ret)
+               return ret;
 
        for (i = 0;i < chip->num_slots;i++) {
                if (!chip->hosts[i])
@@ -1274,15 +1280,6 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        if (caps & SDHCI_TIMEOUT_CLK_UNIT)
                host->timeout_clk *= 1000;
 
-       host->max_block = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
-       if (host->max_block >= 3) {
-               printk(KERN_ERR "%s: Invalid maximum block size.\n",
-                       host->slot_descr);
-               ret = -ENODEV;
-               goto unmap;
-       }
-       host->max_block = 512 << host->max_block;
-
        /*
         * Set host parameters.
         */
@@ -1294,9 +1291,9 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        mmc->ocr_avail = 0;
        if (caps & SDHCI_CAN_VDD_330)
                mmc->ocr_avail |= MMC_VDD_32_33|MMC_VDD_33_34;
-       else if (caps & SDHCI_CAN_VDD_300)
+       if (caps & SDHCI_CAN_VDD_300)
                mmc->ocr_avail |= MMC_VDD_29_30|MMC_VDD_30_31;
-       else if (caps & SDHCI_CAN_VDD_180)
+       if (caps & SDHCI_CAN_VDD_180)
                mmc->ocr_avail |= MMC_VDD_17_18|MMC_VDD_18_19;
 
        if ((host->max_clk > 25000000) && !(caps & SDHCI_CAN_DO_HISPD)) {
@@ -1326,15 +1323,33 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 
        /*
         * Maximum number of sectors in one transfer. Limited by DMA boundary
-        * size (512KiB), which means (512 KiB/512=) 1024 entries.
+        * size (512KiB).
         */
-       mmc->max_sectors = 1024;
+       mmc->max_req_size = 524288;
 
        /*
         * Maximum segment size. Could be one segment with the maximum number
-        * of sectors.
+        * of bytes.
+        */
+       mmc->max_seg_size = mmc->max_req_size;
+
+       /*
+        * Maximum block size. This varies from controller to controller and
+        * is specified in the capabilities register.
+        */
+       mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
+       if (mmc->max_blk_size >= 3) {
+               printk(KERN_ERR "%s: Invalid maximum block size.\n",
+                       host->slot_descr);
+               ret = -ENODEV;
+               goto unmap;
+       }
+       mmc->max_blk_size = 512 << mmc->max_blk_size;
+
+       /*
+        * Maximum block count.
         */
-       mmc->max_seg_size = mmc->max_sectors * 512;
+       mmc->max_blk_count = 65535;
 
        /*
         * Init tasklets.
index f9d1a0a..e324f0a 100644 (file)
@@ -174,7 +174,6 @@ struct sdhci_host {
 
        unsigned int            max_clk;        /* Max possible freq (MHz) */
        unsigned int            timeout_clk;    /* Timeout freq (KHz) */
-       unsigned int            max_block;      /* Max block size (bytes) */
 
        unsigned int            clock;          /* Current clock (MHz) */
        unsigned short          power;          /* Current voltage */
@@ -184,7 +183,6 @@ struct sdhci_host {
        struct mmc_data         *data;          /* Current data request */
 
        struct scatterlist      *cur_sg;        /* We're working on this */
-       char                    *mapped_sg;     /* This is where it's mapped */
        int                     num_sg;         /* Entries left */
        int                     offset;         /* Offset into current sg */
        int                     remain;         /* Bytes left in current */
index fa4a528..e65f8a0 100644 (file)
@@ -17,7 +17,7 @@
 #include <asm/io.h>
 
 #define DRIVER_NAME "tifm_sd"
-#define DRIVER_VERSION "0.6"
+#define DRIVER_VERSION "0.7"
 
 static int no_dma = 0;
 static int fixed_timeout = 0;
@@ -79,7 +79,6 @@ typedef enum {
 
 enum {
        FIFO_RDY   = 0x0001,     /* hardware dependent value */
-       HOST_REG   = 0x0002,
        EJECT      = 0x0004,
        EJECT_DONE = 0x0008,
        CARD_BUSY  = 0x0010,
@@ -95,46 +94,53 @@ struct tifm_sd {
        card_state_t        state;
        unsigned int        clk_freq;
        unsigned int        clk_div;
-       unsigned long       timeout_jiffies; // software timeout - 2 sec
+       unsigned long       timeout_jiffies;
 
+       struct tasklet_struct finish_tasklet;
+       struct timer_list     timer;
        struct mmc_request    *req;
-       struct work_struct    cmd_handler;
-       struct delayed_work   abort_handler;
-       wait_queue_head_t     can_eject;
+       wait_queue_head_t     notify;
 
        size_t                written_blocks;
-       char                  *buffer;
        size_t                buffer_size;
        size_t                buffer_pos;
 
 };
 
+static char* tifm_sd_data_buffer(struct mmc_data *data)
+{
+       return page_address(data->sg->page) + data->sg->offset;
+}
+
 static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
-                                       unsigned int host_status)
+                                unsigned int host_status)
 {
        struct mmc_command *cmd = host->req->cmd;
        unsigned int t_val = 0, cnt = 0;
+       char *buffer;
 
        if (host_status & TIFM_MMCSD_BRS) {
                /* in non-dma rx mode BRS fires when fifo is still not empty */
-               if (host->buffer && (cmd->data->flags & MMC_DATA_READ)) {
+               if (no_dma && (cmd->data->flags & MMC_DATA_READ)) {
+                       buffer = tifm_sd_data_buffer(host->req->data);
                        while (host->buffer_size > host->buffer_pos) {
                                t_val = readl(sock->addr + SOCK_MMCSD_DATA);
-                               host->buffer[host->buffer_pos++] = t_val & 0xff;
-                               host->buffer[host->buffer_pos++] =
+                               buffer[host->buffer_pos++] = t_val & 0xff;
+                               buffer[host->buffer_pos++] =
                                                        (t_val >> 8) & 0xff;
                        }
                }
                return 1;
-       } else if (host->buffer) {
+       } else if (no_dma) {
+               buffer = tifm_sd_data_buffer(host->req->data);
                if ((cmd->data->flags & MMC_DATA_READ) &&
                                (host_status & TIFM_MMCSD_AF)) {
                        for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
                                t_val = readl(sock->addr + SOCK_MMCSD_DATA);
                                if (host->buffer_size > host->buffer_pos) {
-                                       host->buffer[host->buffer_pos++] =
+                                       buffer[host->buffer_pos++] =
                                                        t_val & 0xff;
-                                       host->buffer[host->buffer_pos++] =
+                                       buffer[host->buffer_pos++] =
                                                        (t_val >> 8) & 0xff;
                                }
                        }
@@ -142,11 +148,12 @@ static int tifm_sd_transfer_data(struct tifm_dev *sock, struct tifm_sd *host,
                           && (host_status & TIFM_MMCSD_AE)) {
                        for (cnt = 0; cnt < TIFM_MMCSD_FIFO_SIZE; cnt++) {
                                if (host->buffer_size > host->buffer_pos) {
-                                       t_val = host->buffer[host->buffer_pos++] & 0x00ff;
-                                       t_val |= ((host->buffer[host->buffer_pos++]) << 8)
-                                                & 0xff00;
+                                       t_val = buffer[host->buffer_pos++]
+                                               & 0x00ff;
+                                       t_val |= ((buffer[host->buffer_pos++])
+                                                 << 8) & 0xff00;
                                        writel(t_val,
-                                               sock->addr + SOCK_MMCSD_DATA);
+                                              sock->addr + SOCK_MMCSD_DATA);
                                }
                        }
                }
@@ -206,7 +213,7 @@ static void tifm_sd_exec(struct tifm_sd *host, struct mmc_command *cmd)
                cmd_mask |= TIFM_MMCSD_READ;
 
        dev_dbg(&sock->dev, "executing opcode 0x%x, arg: 0x%x, mask: 0x%x\n",
-                               cmd->opcode, cmd->arg, cmd_mask);
+               cmd->opcode, cmd->arg, cmd_mask);
 
        writel((cmd->arg >> 16) & 0xffff, sock->addr + SOCK_MMCSD_ARG_HIGH);
        writel(cmd->arg & 0xffff, sock->addr + SOCK_MMCSD_ARG_LOW);
@@ -239,65 +246,78 @@ change_state:
                        tifm_sd_fetch_resp(cmd, sock);
                        if (cmd->data) {
                                host->state = BRS;
-                       } else
+                       } else {
                                host->state = READY;
+                       }
                        goto change_state;
                }
                break;
        case BRS:
                if (tifm_sd_transfer_data(sock, host, host_status)) {
-                       if (!host->req->stop) {
-                               if (cmd->data->flags & MMC_DATA_WRITE) {
-                                       host->state = CARD;
+                       if (cmd->data->flags & MMC_DATA_WRITE) {
+                               host->state = CARD;
+                       } else {
+                               if (no_dma) {
+                                       if (host->req->stop) {
+                                               tifm_sd_exec(host, host->req->stop);
+                                               host->state = SCMD;
+                                       } else {
+                                               host->state = READY;
+                                       }
                                } else {
-                                       host->state =
-                                               host->buffer ? READY : FIFO;
+                                       host->state = FIFO;
                                }
-                               goto change_state;
                        }
-                       tifm_sd_exec(host, host->req->stop);
-                       host->state = SCMD;
+                       goto change_state;
                }
                break;
        case SCMD:
                if (host_status & TIFM_MMCSD_EOC) {
                        tifm_sd_fetch_resp(host->req->stop, sock);
-                       if (cmd->error) {
-                               host->state = READY;
-                       } else if (cmd->data->flags & MMC_DATA_WRITE) {
-                               host->state = CARD;
-                       } else {
-                               host->state = host->buffer ? READY : FIFO;
-                       }
+                       host->state = READY;
                        goto change_state;
                }
                break;
        case CARD:
+               dev_dbg(&sock->dev, "waiting for CARD, have %zd blocks\n",
+                       host->written_blocks);
                if (!(host->flags & CARD_BUSY)
                    && (host->written_blocks == cmd->data->blocks)) {
-                       host->state = host->buffer ? READY : FIFO;
+                       if (no_dma) {
+                               if (host->req->stop) {
+                                       tifm_sd_exec(host, host->req->stop);
+                                       host->state = SCMD;
+                               } else {
+                                       host->state = READY;
+                               }
+                       } else {
+                               host->state = FIFO;
+                       }
                        goto change_state;
                }
                break;
        case FIFO:
                if (host->flags & FIFO_RDY) {
-                       host->state = READY;
                        host->flags &= ~FIFO_RDY;
+                       if (host->req->stop) {
+                               tifm_sd_exec(host, host->req->stop);
+                               host->state = SCMD;
+                       } else {
+                               host->state = READY;
+                       }
                        goto change_state;
                }
                break;
        case READY:
-               queue_work(sock->wq, &host->cmd_handler);
+               tasklet_schedule(&host->finish_tasklet);
                return;
        }
 
-       queue_delayed_work(sock->wq, &host->abort_handler,
-                               host->timeout_jiffies);
 }
 
 /* Called from interrupt handler */
-static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
-                                       unsigned int sock_irq_status)
+static void tifm_sd_signal_irq(struct tifm_dev *sock,
+                              unsigned int sock_irq_status)
 {
        struct tifm_sd *host;
        unsigned int host_status = 0, fifo_status = 0;
@@ -305,7 +325,6 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
 
        spin_lock(&sock->lock);
        host = mmc_priv((struct mmc_host*)tifm_get_drvdata(sock));
-       cancel_delayed_work(&host->abort_handler);
 
        if (sock_irq_status & FIFO_EVENT) {
                fifo_status = readl(sock->addr + SOCK_DMA_FIFO_STATUS);
@@ -318,19 +337,17 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
                host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
                writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
 
-               if (!(host->flags & HOST_REG))
-                       queue_work(sock->wq, &host->cmd_handler);
                if (!host->req)
                        goto done;
 
                if (host_status & TIFM_MMCSD_ERRMASK) {
                        if (host_status & TIFM_MMCSD_CERR)
                                error_code = MMC_ERR_FAILED;
-                       else if (host_status &
-                                       (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
+                       else if (host_status
+                                & (TIFM_MMCSD_CTO | TIFM_MMCSD_DTO))
                                error_code = MMC_ERR_TIMEOUT;
-                       else if (host_status &
-                                       (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
+                       else if (host_status
+                                & (TIFM_MMCSD_CCRC | TIFM_MMCSD_DCRC))
                                error_code = MMC_ERR_BADCRC;
 
                        writel(TIFM_FIFO_INT_SETALL,
@@ -340,12 +357,11 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
                        if (host->req->stop) {
                                if (host->state == SCMD) {
                                        host->req->stop->error = error_code;
-                               } else if(host->state == BRS) {
+                               } else if (host->state == BRS
+                                          || host->state == CARD
+                                          || host->state == FIFO) {
                                        host->req->cmd->error = error_code;
                                        tifm_sd_exec(host, host->req->stop);
-                                       queue_delayed_work(sock->wq,
-                                               &host->abort_handler,
-                                               host->timeout_jiffies);
                                        host->state = SCMD;
                                        goto done;
                                } else {
@@ -359,8 +375,8 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
 
                if (host_status & TIFM_MMCSD_CB)
                        host->flags |= CARD_BUSY;
-               if ((host_status & TIFM_MMCSD_EOFB) &&
-                               (host->flags & CARD_BUSY)) {
+               if ((host_status & TIFM_MMCSD_EOFB)
+                   && (host->flags & CARD_BUSY)) {
                        host->written_blocks++;
                        host->flags &= ~CARD_BUSY;
                }
@@ -370,22 +386,22 @@ static unsigned int tifm_sd_signal_irq(struct tifm_dev *sock,
                tifm_sd_process_cmd(sock, host, host_status);
 done:
        dev_dbg(&sock->dev, "host_status %x, fifo_status %x\n",
-                       host_status, fifo_status);
+               host_status, fifo_status);
        spin_unlock(&sock->lock);
-       return sock_irq_status;
 }
 
-static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
+static void tifm_sd_prepare_data(struct tifm_sd *host, struct mmc_command *cmd)
 {
-       struct tifm_dev *sock = card->dev;
+       struct tifm_dev *sock = host->dev;
        unsigned int dest_cnt;
 
        /* DMA style IO */
-
+       dev_dbg(&sock->dev, "setting dma for %d blocks\n",
+               cmd->data->blocks);
        writel(TIFM_FIFO_INT_SETALL,
-               sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+              sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
        writel(ilog2(cmd->data->blksz) - 2,
-                       sock->addr + SOCK_FIFO_PAGE_SIZE);
+              sock->addr + SOCK_FIFO_PAGE_SIZE);
        writel(TIFM_FIFO_ENABLE, sock->addr + SOCK_FIFO_CONTROL);
        writel(TIFM_FIFO_INTMASK, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
 
@@ -399,7 +415,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
        if (cmd->data->flags & MMC_DATA_WRITE) {
                writel(TIFM_MMCSD_TXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
                writel(dest_cnt | TIFM_DMA_TX | TIFM_DMA_EN,
-                       sock->addr + SOCK_DMA_CONTROL);
+                      sock->addr + SOCK_DMA_CONTROL);
        } else {
                writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
                writel(dest_cnt | TIFM_DMA_EN, sock->addr + SOCK_DMA_CONTROL);
@@ -407,7 +423,7 @@ static void tifm_sd_prepare_data(struct tifm_sd *card, struct mmc_command *cmd)
 }
 
 static void tifm_sd_set_data_timeout(struct tifm_sd *host,
-                                       struct mmc_data *data)
+                                    struct mmc_data *data)
 {
        struct tifm_dev *sock = host->dev;
        unsigned int data_timeout = data->timeout_clks;
@@ -416,22 +432,21 @@ static void tifm_sd_set_data_timeout(struct tifm_sd *host,
                return;
 
        data_timeout += data->timeout_ns /
-                       ((1000000000 / host->clk_freq) * host->clk_div);
-       data_timeout *= 10; // call it fudge factor for now
+                       ((1000000000UL / host->clk_freq) * host->clk_div);
 
        if (data_timeout < 0xffff) {
-               writel((~TIFM_MMCSD_DPE) &
-                               readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
-                      sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
                writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+               writel((~TIFM_MMCSD_DPE)
+                      & readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+                      sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
        } else {
-               writel(TIFM_MMCSD_DPE |
-                               readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
-                       sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
                data_timeout = (data_timeout >> 10) + 1;
-               if(data_timeout > 0xffff)
+               if (data_timeout > 0xffff)
                        data_timeout = 0;       /* set to unlimited */
                writel(data_timeout, sock->addr + SOCK_MMCSD_DATA_TO);
+               writel(TIFM_MMCSD_DPE
+                      | readl(sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG),
+                      sock->addr + SOCK_MMCSD_SDIO_MODE_CONFIG);
        }
 }
 
@@ -474,11 +489,10 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq)
        }
 
        host->req = mrq;
+       mod_timer(&host->timer, jiffies + host->timeout_jiffies);
        host->state = CMD;
-       queue_delayed_work(sock->wq, &host->abort_handler,
-                               host->timeout_jiffies);
        writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
-               sock->addr + SOCK_CONTROL);
+              sock->addr + SOCK_CONTROL);
        tifm_sd_exec(host, mrq->cmd);
        spin_unlock_irqrestore(&sock->lock, flags);
        return;
@@ -493,9 +507,9 @@ err_out:
        mmc_request_done(mmc, mrq);
 }
 
-static void tifm_sd_end_cmd(struct work_struct *work)
+static void tifm_sd_end_cmd(unsigned long data)
 {
-       struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+       struct tifm_sd *host = (struct tifm_sd*)data;
        struct tifm_dev *sock = host->dev;
        struct mmc_host *mmc = tifm_get_drvdata(sock);
        struct mmc_request *mrq;
@@ -504,6 +518,7 @@ static void tifm_sd_end_cmd(struct work_struct *work)
 
        spin_lock_irqsave(&sock->lock, flags);
 
+       del_timer(&host->timer);
        mrq = host->req;
        host->req = NULL;
        host->state = IDLE;
@@ -517,8 +532,8 @@ static void tifm_sd_end_cmd(struct work_struct *work)
        r_data = mrq->cmd->data;
        if (r_data) {
                if (r_data->flags & MMC_DATA_WRITE) {
-                       r_data->bytes_xfered = host->written_blocks *
-                                               r_data->blksz;
+                       r_data->bytes_xfered = host->written_blocks
+                                              * r_data->blksz;
                } else {
                        r_data->bytes_xfered = r_data->blocks -
                                readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
@@ -532,7 +547,7 @@ static void tifm_sd_end_cmd(struct work_struct *work)
        }
 
        writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
-                       sock->addr + SOCK_CONTROL);
+              sock->addr + SOCK_CONTROL);
 
        spin_unlock_irqrestore(&sock->lock, flags);
        mmc_request_done(mmc, mrq);
@@ -544,15 +559,6 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
        struct tifm_dev *sock = host->dev;
        unsigned long flags;
        struct mmc_data *r_data = mrq->cmd->data;
-       char *t_buffer = NULL;
-
-       if (r_data) {
-               t_buffer = kmap(r_data->sg->page);
-               if (!t_buffer) {
-                       printk(KERN_ERR DRIVER_NAME ": kmap failed\n");
-                       goto err_out;
-               }
-       }
 
        spin_lock_irqsave(&sock->lock, flags);
        if (host->flags & EJECT) {
@@ -569,15 +575,14 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
        if (r_data) {
                tifm_sd_set_data_timeout(host, r_data);
 
-               host->buffer = t_buffer + r_data->sg->offset;
-               host->buffer_size = mrq->cmd->data->blocks *
-                                       mrq->cmd->data->blksz;
+               host->buffer_size = mrq->cmd->data->blocks
+                                   * mrq->cmd->data->blksz;
 
-               writel(TIFM_MMCSD_BUFINT |
-                               readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
+               writel(TIFM_MMCSD_BUFINT
+                      | readl(sock->addr + SOCK_MMCSD_INT_ENABLE),
                       sock->addr + SOCK_MMCSD_INT_ENABLE);
-               writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8) |
-                               (TIFM_MMCSD_FIFO_SIZE - 1),
+               writel(((TIFM_MMCSD_FIFO_SIZE - 1) << 8)
+                      | (TIFM_MMCSD_FIFO_SIZE - 1),
                       sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
 
                host->written_blocks = 0;
@@ -588,26 +593,22 @@ static void tifm_sd_request_nodma(struct mmc_host *mmc, struct mmc_request *mrq)
        }
 
        host->req = mrq;
+       mod_timer(&host->timer, jiffies + host->timeout_jiffies);
        host->state = CMD;
-       queue_delayed_work(sock->wq, &host->abort_handler,
-                               host->timeout_jiffies);
        writel(TIFM_CTRL_LED | readl(sock->addr + SOCK_CONTROL),
-               sock->addr + SOCK_CONTROL);
+              sock->addr + SOCK_CONTROL);
        tifm_sd_exec(host, mrq->cmd);
        spin_unlock_irqrestore(&sock->lock, flags);
        return;
 
 err_out:
-       if (t_buffer)
-               kunmap(r_data->sg->page);
-
        mrq->cmd->error = MMC_ERR_TIMEOUT;
        mmc_request_done(mmc, mrq);
 }
 
-static void tifm_sd_end_cmd_nodma(struct work_struct *work)
+static void tifm_sd_end_cmd_nodma(unsigned long data)
 {
-       struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+       struct tifm_sd *host = (struct tifm_sd*)data;
        struct tifm_dev *sock = host->dev;
        struct mmc_host *mmc = tifm_get_drvdata(sock);
        struct mmc_request *mrq;
@@ -616,6 +617,7 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
 
        spin_lock_irqsave(&sock->lock, flags);
 
+       del_timer(&host->timer);
        mrq = host->req;
        host->req = NULL;
        host->state = IDLE;
@@ -633,8 +635,8 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
                        sock->addr + SOCK_MMCSD_INT_ENABLE);
 
                if (r_data->flags & MMC_DATA_WRITE) {
-                       r_data->bytes_xfered = host->written_blocks *
-                                               r_data->blksz;
+                       r_data->bytes_xfered = host->written_blocks
+                                              * r_data->blksz;
                } else {
                        r_data->bytes_xfered = r_data->blocks -
                                readl(sock->addr + SOCK_MMCSD_NUM_BLOCKS) - 1;
@@ -642,29 +644,44 @@ static void tifm_sd_end_cmd_nodma(struct work_struct *work)
                        r_data->bytes_xfered += r_data->blksz -
                                readl(sock->addr + SOCK_MMCSD_BLOCK_LEN) + 1;
                }
-               host->buffer = NULL;
                host->buffer_pos = 0;
                host->buffer_size = 0;
        }
 
        writel((~TIFM_CTRL_LED) & readl(sock->addr + SOCK_CONTROL),
-                       sock->addr + SOCK_CONTROL);
+              sock->addr + SOCK_CONTROL);
 
        spin_unlock_irqrestore(&sock->lock, flags);
 
-        if (r_data)
-               kunmap(r_data->sg->page);
-
        mmc_request_done(mmc, mrq);
 }
 
-static void tifm_sd_abort(struct work_struct *work)
+static void tifm_sd_terminate(struct tifm_sd *host)
+{
+       struct tifm_dev *sock = host->dev;
+       unsigned long flags;
+
+       writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+       mmiowb();
+       spin_lock_irqsave(&sock->lock, flags);
+       host->flags |= EJECT;
+       if (host->req) {
+               writel(TIFM_FIFO_INT_SETALL,
+                      sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
+               writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+               tasklet_schedule(&host->finish_tasklet);
+       }
+       spin_unlock_irqrestore(&sock->lock, flags);
+}
+
+static void tifm_sd_abort(unsigned long data)
 {
-       struct tifm_sd *host =
-               container_of(work, struct tifm_sd, abort_handler.work);
+       struct tifm_sd *host = (struct tifm_sd*)data;
 
        printk(KERN_ERR DRIVER_NAME
-               ": card failed to respond for a long period of time");
+              ": card failed to respond for a long period of time");
+
+       tifm_sd_terminate(host);
        tifm_eject(host->dev);
 }
 
@@ -683,9 +700,9 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                writel(TIFM_MMCSD_4BBUS | readl(sock->addr + SOCK_MMCSD_CONFIG),
                       sock->addr + SOCK_MMCSD_CONFIG);
        } else {
-               writel((~TIFM_MMCSD_4BBUS) &
-                               readl(sock->addr + SOCK_MMCSD_CONFIG),
-                       sock->addr + SOCK_MMCSD_CONFIG);
+               writel((~TIFM_MMCSD_4BBUS)
+                      & readl(sock->addr + SOCK_MMCSD_CONFIG),
+                      sock->addr + SOCK_MMCSD_CONFIG);
        }
 
        if (ios->clock) {
@@ -704,23 +721,24 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                if ((20000000 / clk_div1) > (24000000 / clk_div2)) {
                        host->clk_freq = 20000000;
                        host->clk_div = clk_div1;
-                       writel((~TIFM_CTRL_FAST_CLK) &
-                                       readl(sock->addr + SOCK_CONTROL),
-                               sock->addr + SOCK_CONTROL);
+                       writel((~TIFM_CTRL_FAST_CLK)
+                              & readl(sock->addr + SOCK_CONTROL),
+                              sock->addr + SOCK_CONTROL);
                } else {
                        host->clk_freq = 24000000;
                        host->clk_div = clk_div2;
-                       writel(TIFM_CTRL_FAST_CLK |
-                                       readl(sock->addr + SOCK_CONTROL),
-                               sock->addr + SOCK_CONTROL);
+                       writel(TIFM_CTRL_FAST_CLK
+                              | readl(sock->addr + SOCK_CONTROL),
+                              sock->addr + SOCK_CONTROL);
                }
        } else {
                host->clk_div = 0;
        }
        host->clk_div &= TIFM_MMCSD_CLKMASK;
-       writel(host->clk_div | ((~TIFM_MMCSD_CLKMASK) &
-                       readl(sock->addr + SOCK_MMCSD_CONFIG)),
-               sock->addr + SOCK_MMCSD_CONFIG);
+       writel(host->clk_div
+              | ((~TIFM_MMCSD_CLKMASK)
+                 & readl(sock->addr + SOCK_MMCSD_CONFIG)),
+              sock->addr + SOCK_MMCSD_CONFIG);
 
        if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
                host->flags |= OPENDRAIN;
@@ -734,7 +752,7 @@ static void tifm_sd_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        // allow removal.
        if ((host->flags & EJECT) && ios->power_mode == MMC_POWER_OFF) {
                host->flags |= EJECT_DONE;
-               wake_up_all(&host->can_eject);
+               wake_up_all(&host->notify);
        }
 
        spin_unlock_irqrestore(&sock->lock, flags);
@@ -762,20 +780,67 @@ static struct mmc_host_ops tifm_sd_ops = {
        .get_ro  = tifm_sd_ro
 };
 
-static void tifm_sd_register_host(struct work_struct *work)
+static int tifm_sd_initialize_host(struct tifm_sd *host)
 {
-       struct tifm_sd *host = container_of(work, struct tifm_sd, cmd_handler);
+       int rc;
+       unsigned int host_status = 0;
        struct tifm_dev *sock = host->dev;
-       struct mmc_host *mmc = tifm_get_drvdata(sock);
-       unsigned long flags;
 
-       spin_lock_irqsave(&sock->lock, flags);
-       host->flags |= HOST_REG;
-       PREPARE_WORK(&host->cmd_handler,
-                       no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd);
-       spin_unlock_irqrestore(&sock->lock, flags);
-       dev_dbg(&sock->dev, "adding host\n");
-       mmc_add_host(mmc);
+       writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
+       mmiowb();
+       host->clk_div = 61;
+       host->clk_freq = 20000000;
+       writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
+       writel(host->clk_div | TIFM_MMCSD_POWER,
+              sock->addr + SOCK_MMCSD_CONFIG);
+
+       /* wait up to 0.51 sec for reset */
+       for (rc = 2; rc <= 256; rc <<= 1) {
+               if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
+                       rc = 0;
+                       break;
+               }
+               msleep(rc);
+       }
+
+       if (rc) {
+               printk(KERN_ERR DRIVER_NAME
+                      ": controller failed to reset\n");
+               return -ENODEV;
+       }
+
+       writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
+       writel(host->clk_div | TIFM_MMCSD_POWER,
+              sock->addr + SOCK_MMCSD_CONFIG);
+       writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
+
+       // command timeout fixed to 64 clocks for now
+       writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO);
+       writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
+
+       /* INAB should take much less than reset */
+       for (rc = 1; rc <= 16; rc <<= 1) {
+               host_status = readl(sock->addr + SOCK_MMCSD_STATUS);
+               writel(host_status, sock->addr + SOCK_MMCSD_STATUS);
+               if (!(host_status & TIFM_MMCSD_ERRMASK)
+                   && (host_status & TIFM_MMCSD_EOC)) {
+                       rc = 0;
+                       break;
+               }
+               msleep(rc);
+       }
+
+       if (rc) {
+               printk(KERN_ERR DRIVER_NAME
+                      ": card not ready - probe failed on initialization\n");
+               return -ENODEV;
+       }
+
+       writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
+              sock->addr + SOCK_MMCSD_INT_ENABLE);
+       mmiowb();
+
+       return 0;
 }
 
 static int tifm_sd_probe(struct tifm_dev *sock)
@@ -784,8 +849,8 @@ static int tifm_sd_probe(struct tifm_dev *sock)
        struct tifm_sd *host;
        int rc = -EIO;
 
-       if (!(TIFM_SOCK_STATE_OCCUPIED &
-                       readl(sock->addr + SOCK_PRESENT_STATE))) {
+       if (!(TIFM_SOCK_STATE_OCCUPIED
+             & readl(sock->addr + SOCK_PRESENT_STATE))) {
                printk(KERN_WARNING DRIVER_NAME ": card gone, unexpectedly\n");
                return rc;
        }
@@ -795,109 +860,99 @@ static int tifm_sd_probe(struct tifm_dev *sock)
                return -ENOMEM;
 
        host = mmc_priv(mmc);
-       host->dev = sock;
-       host->clk_div = 61;
-       init_waitqueue_head(&host->can_eject);
-       INIT_WORK(&host->cmd_handler, tifm_sd_register_host);
-       INIT_DELAYED_WORK(&host->abort_handler, tifm_sd_abort);
-
        tifm_set_drvdata(sock, mmc);
-       sock->signal_irq = tifm_sd_signal_irq;
-
-       host->clk_freq = 20000000;
+       host->dev = sock;
        host->timeout_jiffies = msecs_to_jiffies(1000);
 
+       init_waitqueue_head(&host->notify);
+       tasklet_init(&host->finish_tasklet,
+                    no_dma ? tifm_sd_end_cmd_nodma : tifm_sd_end_cmd,
+                    (unsigned long)host);
+       setup_timer(&host->timer, tifm_sd_abort, (unsigned long)host);
+
        tifm_sd_ops.request = no_dma ? tifm_sd_request_nodma : tifm_sd_request;
        mmc->ops = &tifm_sd_ops;
        mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-       mmc->caps = MMC_CAP_4_BIT_DATA;
+       mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_MULTIWRITE;
        mmc->f_min = 20000000 / 60;
        mmc->f_max = 24000000;
        mmc->max_hw_segs = 1;
        mmc->max_phys_segs = 1;
-       mmc->max_sectors = 127;
-       mmc->max_seg_size = mmc->max_sectors << 11; //2k maximum hw block length
-
-       writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
-       writel(TIFM_MMCSD_RESET, sock->addr + SOCK_MMCSD_SYSTEM_CONTROL);
-       writel(host->clk_div | TIFM_MMCSD_POWER,
-                       sock->addr + SOCK_MMCSD_CONFIG);
+       // limited by DMA counter - it's safer to stick with
+       // block counter has 11 bits though
+       mmc->max_blk_count = 256;
+       // 2k maximum hw block length
+       mmc->max_blk_size = 2048;
+       mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
+       mmc->max_seg_size = mmc->max_req_size;
+       sock->signal_irq = tifm_sd_signal_irq;
+       rc = tifm_sd_initialize_host(host);
 
-       for (rc = 0; rc < 50; rc++) {
-               /* Wait for reset ack */
-               if (1 & readl(sock->addr + SOCK_MMCSD_SYSTEM_STATUS)) {
-                       rc = 0;
-                       break;
-               }
-               msleep(10);
-        }
+       if (!rc)
+               rc = mmc_add_host(mmc);
+       if (rc)
+               goto out_free_mmc;
 
-       if (rc) {
-               printk(KERN_ERR DRIVER_NAME
-                       ": card not ready - probe failed\n");
-               mmc_free_host(mmc);
-               return -ENODEV;
-       }
+       return 0;
+out_free_mmc:
+       mmc_free_host(mmc);
+       return rc;
+}
 
-       writel(0, sock->addr + SOCK_MMCSD_NUM_BLOCKS);
-       writel(host->clk_div | TIFM_MMCSD_POWER,
-                       sock->addr + SOCK_MMCSD_CONFIG);
-       writel(TIFM_MMCSD_RXDE, sock->addr + SOCK_MMCSD_BUFFER_CONFIG);
-       writel(TIFM_MMCSD_DATAMASK | TIFM_MMCSD_ERRMASK,
-                       sock->addr + SOCK_MMCSD_INT_ENABLE);
+static void tifm_sd_remove(struct tifm_dev *sock)
+{
+       struct mmc_host *mmc = tifm_get_drvdata(sock);
+       struct tifm_sd *host = mmc_priv(mmc);
 
-       writel(64, sock->addr + SOCK_MMCSD_COMMAND_TO); // command timeout 64 clocks for now
-       writel(TIFM_MMCSD_INAB, sock->addr + SOCK_MMCSD_COMMAND);
-       writel(host->clk_div | TIFM_MMCSD_POWER,
-                       sock->addr + SOCK_MMCSD_CONFIG);
+       del_timer_sync(&host->timer);
+       tifm_sd_terminate(host);
+       wait_event_timeout(host->notify, host->flags & EJECT_DONE,
+                          host->timeout_jiffies);
+       tasklet_kill(&host->finish_tasklet);
+       mmc_remove_host(mmc);
 
-       queue_delayed_work(sock->wq, &host->abort_handler,
-                       host->timeout_jiffies);
+       /* The meaning of the bit majority in this constant is unknown. */
+       writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+              sock->addr + SOCK_CONTROL);
 
-       return 0;
+       tifm_set_drvdata(sock, NULL);
+       mmc_free_host(mmc);
 }
 
-static int tifm_sd_host_is_down(struct tifm_dev *sock)
+#ifdef CONFIG_PM
+
+static int tifm_sd_suspend(struct tifm_dev *sock, pm_message_t state)
 {
        struct mmc_host *mmc = tifm_get_drvdata(sock);
-       struct tifm_sd *host = mmc_priv(mmc);
-       unsigned long flags;
-       int rc = 0;
+       int rc;
 
-       spin_lock_irqsave(&sock->lock, flags);
-       rc = (host->flags & EJECT_DONE);
-       spin_unlock_irqrestore(&sock->lock, flags);
+       rc = mmc_suspend_host(mmc, state);
+       /* The meaning of the bit majority in this constant is unknown. */
+       writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
+              sock->addr + SOCK_CONTROL);
        return rc;
 }
 
-static void tifm_sd_remove(struct tifm_dev *sock)
+static int tifm_sd_resume(struct tifm_dev *sock)
 {
        struct mmc_host *mmc = tifm_get_drvdata(sock);
        struct tifm_sd *host = mmc_priv(mmc);
-       unsigned long flags;
 
-       spin_lock_irqsave(&sock->lock, flags);
-       host->flags |= EJECT;
-       if (host->req)
-               queue_work(sock->wq, &host->cmd_handler);
-       spin_unlock_irqrestore(&sock->lock, flags);
-       wait_event_timeout(host->can_eject, tifm_sd_host_is_down(sock),
-                               host->timeout_jiffies);
+       if (sock->media_id != FM_SD
+           || tifm_sd_initialize_host(host)) {
+               tifm_eject(sock);
+               return 0;
+       } else {
+               return mmc_resume_host(mmc);
+       }
+}
 
-       if (host->flags & HOST_REG)
-               mmc_remove_host(mmc);
+#else
 
-       /* The meaning of the bit majority in this constant is unknown. */
-       writel(0xfff8 & readl(sock->addr + SOCK_CONTROL),
-               sock->addr + SOCK_CONTROL);
-       writel(0, sock->addr + SOCK_MMCSD_INT_ENABLE);
-       writel(TIFM_FIFO_INT_SETALL,
-               sock->addr + SOCK_DMA_FIFO_INT_ENABLE_CLEAR);
-       writel(0, sock->addr + SOCK_DMA_FIFO_INT_ENABLE_SET);
+#define tifm_sd_suspend NULL
+#define tifm_sd_resume NULL
 
-       tifm_set_drvdata(sock, NULL);
-       mmc_free_host(mmc);
-}
+#endif /* CONFIG_PM */
 
 static tifm_media_id tifm_sd_id_tbl[] = {
        FM_SD, 0
@@ -910,7 +965,9 @@ static struct tifm_driver tifm_sd_driver = {
        },
        .id_table = tifm_sd_id_tbl,
        .probe    = tifm_sd_probe,
-       .remove   = tifm_sd_remove
+       .remove   = tifm_sd_remove,
+       .suspend  = tifm_sd_suspend,
+       .resume   = tifm_sd_resume
 };
 
 static int __init tifm_sd_init(void)
index 7a28267..a44d877 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  linux/drivers/mmc/wbsd.c - Winbond W83L51xD SD/MMC driver
  *
- *  Copyright (C) 2004-2005 Pierre Ossman, All Rights Reserved.
+ *  Copyright (C) 2004-2006 Pierre Ossman, All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -272,16 +272,9 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
        return host->num_sg;
 }
 
-static inline char *wbsd_kmap_sg(struct wbsd_host *host)
+static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
 {
-       host->mapped_sg = kmap_atomic(host->cur_sg->page, KM_BIO_SRC_IRQ) +
-               host->cur_sg->offset;
-       return host->mapped_sg;
-}
-
-static inline void wbsd_kunmap_sg(struct wbsd_host *host)
-{
-       kunmap_atomic(host->mapped_sg, KM_BIO_SRC_IRQ);
+       return page_address(host->cur_sg->page) + host->cur_sg->offset;
 }
 
 static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
@@ -302,12 +295,11 @@ static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
         * we do not transfer too much.
         */
        for (i = 0; i < len; i++) {
-               sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+               sgbuf = page_address(sg[i].page) + sg[i].offset;
                if (size < sg[i].length)
                        memcpy(dmabuf, sgbuf, size);
                else
                        memcpy(dmabuf, sgbuf, sg[i].length);
-               kunmap_atomic(sgbuf, KM_BIO_SRC_IRQ);
                dmabuf += sg[i].length;
 
                if (size < sg[i].length)
@@ -347,7 +339,7 @@ static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
         * we do not transfer too much.
         */
        for (i = 0; i < len; i++) {
-               sgbuf = kmap_atomic(sg[i].page, KM_BIO_SRC_IRQ) + sg[i].offset;
+               sgbuf = page_address(sg[i].page) + sg[i].offset;
                if (size < sg[i].length)
                        memcpy(sgbuf, dmabuf, size);
                else
@@ -497,7 +489,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
        if (data->bytes_xfered == host->size)
                return;
 
-       buffer = wbsd_kmap_sg(host) + host->offset;
+       buffer = wbsd_sg_to_buffer(host) + host->offset;
 
        /*
         * Drain the fifo. This has a tendency to loop longer
@@ -526,17 +518,13 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
                        /*
                         * Transfer done?
                         */
-                       if (data->bytes_xfered == host->size) {
-                               wbsd_kunmap_sg(host);
+                       if (data->bytes_xfered == host->size)
                                return;
-                       }
 
                        /*
                         * End of scatter list entry?
                         */
                        if (host->remain == 0) {
-                               wbsd_kunmap_sg(host);
-
                                /*
                                 * Get next entry. Check if last.
                                 */
@@ -554,13 +542,11 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
                                        return;
                                }
 
-                               buffer = wbsd_kmap_sg(host);
+                               buffer = wbsd_sg_to_buffer(host);
                        }
                }
        }
 
-       wbsd_kunmap_sg(host);
-
        /*
         * This is a very dirty hack to solve a
         * hardware problem. The chip doesn't trigger
@@ -583,7 +569,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
        if (data->bytes_xfered == host->size)
                return;
 
-       buffer = wbsd_kmap_sg(host) + host->offset;
+       buffer = wbsd_sg_to_buffer(host) + host->offset;
 
        /*
         * Fill the fifo. This has a tendency to loop longer
@@ -612,17 +598,13 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
                        /*
                         * Transfer done?
                         */
-                       if (data->bytes_xfered == host->size) {
-                               wbsd_kunmap_sg(host);
+                       if (data->bytes_xfered == host->size)
                                return;
-                       }
 
                        /*
                         * End of scatter list entry?
                         */
                        if (host->remain == 0) {
-                               wbsd_kunmap_sg(host);
-
                                /*
                                 * Get next entry. Check if last.
                                 */
@@ -640,13 +622,11 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
                                        return;
                                }
 
-                               buffer = wbsd_kmap_sg(host);
+                               buffer = wbsd_sg_to_buffer(host);
                        }
                }
        }
 
-       wbsd_kunmap_sg(host);
-
        /*
         * The controller stops sending interrupts for
         * 'FIFO empty' under certain conditions. So we
@@ -909,6 +889,45 @@ static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
         * transfered.
         */
        if (cmd->data && (cmd->error == MMC_ERR_NONE)) {
+               /*
+                * The hardware is so delightfully stupid that it has a list
+                * of "data" commands. If a command isn't on this list, it'll
+                * just go back to the idle state and won't send any data
+                * interrupts.
+                */
+               switch (cmd->opcode) {
+               case 11:
+               case 17:
+               case 18:
+               case 20:
+               case 24:
+               case 25:
+               case 26:
+               case 27:
+               case 30:
+               case 42:
+               case 56:
+                       break;
+
+               /* ACMDs. We don't keep track of state, so we just treat them
+                * like any other command. */
+               case 51:
+                       break;
+
+               default:
+#ifdef CONFIG_MMC_DEBUG
+                       printk(KERN_WARNING "%s: Data command %d is not "
+                               "supported by this controller.\n",
+                               mmc_hostname(host->mmc), cmd->opcode);
+#endif
+                       cmd->data->error = MMC_ERR_INVALID;
+
+                       if (cmd->data->stop)
+                               wbsd_send_command(host, cmd->data->stop);
+
+                       goto done;
+               };
+
                /*
                 * Dirty fix for hardware bug.
                 */
@@ -1343,16 +1362,27 @@ static int __devinit wbsd_alloc_mmc(struct device *dev)
        mmc->max_phys_segs = 128;
 
        /*
-        * Maximum number of sectors in one transfer. Also limited by 64kB
-        * buffer.
+        * Maximum request size. Also limited by 64KiB buffer.
         */
-       mmc->max_sectors = 128;
+       mmc->max_req_size = 65536;
 
        /*
         * Maximum segment size. Could be one segment with the maximum number
-        * of segments.
+        * of bytes.
+        */
+       mmc->max_seg_size = mmc->max_req_size;
+
+       /*
+        * Maximum block size. We have 12 bits (= 4095) but have to subtract
+        * space for CRC. So the maximum is 4095 - 4*2 = 4087.
+        */
+       mmc->max_blk_size = 4087;
+
+       /*
+        * Maximum block count. There is no real limit so the maximum
+        * request size will be the only restriction.
         */
-       mmc->max_seg_size = mmc->max_sectors * 512;
+       mmc->max_blk_count = mmc->max_req_size;
 
        dev_set_drvdata(dev, mmc);
 
index 6072993..d06718b 100644 (file)
@@ -154,7 +154,6 @@ struct wbsd_host
 
        struct scatterlist*     cur_sg;         /* Current SG entry */
        unsigned int            num_sg;         /* Number of entries left */
-       void*                   mapped_sg;      /* vaddr of mapped sg */
 
        unsigned int            offset;         /* Offset into current entry */
        unsigned int            remain;         /* Data left in curren entry */
index 80bdcf8..716a472 100644 (file)
@@ -792,8 +792,7 @@ static void poll_vortex(struct net_device *dev)
 {
        struct vortex_private *vp = netdev_priv(dev);
        unsigned long flags;
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
        (vp->full_bus_master_rx ? boomerang_interrupt:vortex_interrupt)(dev->irq,dev);
        local_irq_restore(flags);
 }
index 8aa8dd0..ad92b6a 100644 (file)
@@ -190,7 +190,7 @@ config MII
 
 config MACB
        tristate "Atmel MACB support"
-       depends on NET_ETHERNET && AVR32
+       depends on NET_ETHERNET && (AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263)
        select MII
        help
          The Atmel MACB ethernet interface is found on many AT32 and AT91
@@ -235,16 +235,6 @@ config BMAC
          To compile this driver as a module, choose M here: the module
          will be called bmac.
 
-config OAKNET
-       tristate "National DP83902AV (Oak ethernet) support"
-       depends on NET_ETHERNET && PPC && BROKEN
-       select CRC32
-       help
-         Say Y if your machine has this type of Ethernet network card.
-
-         To compile this driver as a module, choose M here: the module
-         will be called oaknet.
-
 config ARIADNE
        tristate "Ariadne support"
        depends on NET_ETHERNET && ZORRO
@@ -1155,21 +1145,6 @@ config SEEQ8005
          <file:Documentation/networking/net-modules.txt>. The module
          will be called seeq8005.
 
-config SKMC
-       tristate "SKnet MCA support"
-       depends on NET_ETHERNET && MCA && BROKEN
-       ---help---
-         These are Micro Channel Ethernet adapters. You need to say Y to "MCA
-         support" in order to use this driver.  Supported cards are the SKnet
-         Junior MC2 and the SKnet MC2(+).  The driver automatically
-         distinguishes between the two cards. Note that using multiple boards
-         of different type hasn't been tested with this driver.  Say Y if you
-         have one of these Ethernet adapters.
-
-         To compile this driver as a module, choose M here and read
-         <file:Documentation/networking/net-modules.txt>. The module
-         will be called sk_mca.
-
 config NE2_MCA
        tristate "NE/2 (ne2000 MCA version) support"
        depends on NET_ETHERNET && MCA_LEGACY
@@ -1788,6 +1763,18 @@ config LAN_SAA9730
          workstations.
          See <http://www.semiconductors.philips.com/pip/SAA9730_flyer_1>.
 
+config SC92031
+       tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)"
+       depends on NET_PCI && PCI && EXPERIMENTAL
+       select CRC32
+       ---help---
+         This is a driver for the Fast Ethernet PCI network cards based on
+         the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you
+         have one of these, say Y here.
+
+         To compile this driver as a module, choose M here: the module
+         will be called sc92031.  This is recommended.
+
 config NET_POCKET
        bool "Pocket and portable adapters"
        depends on NET_ETHERNET && PARPORT
@@ -2392,6 +2379,24 @@ config CHELSIO_T1_NAPI
          NAPI is a driver API designed to reduce CPU and interrupt load
          when the driver is receiving lots of packets from the card.
 
+config CHELSIO_T3
+        tristate "Chelsio Communications T3 10Gb Ethernet support"
+        depends on PCI
+        help
+          This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
+          adapters.
+
+          For general information about Chelsio and our products, visit
+          our website at <http://www.chelsio.com>.
+
+          For customer support, please visit our customer support page at
+          <http://www.chelsio.com/support.htm>.
+
+          Please send feedback to <linux-bugs@chelsio.com>.
+
+          To compile this driver as a module, choose M here: the module
+          will be called cxgb3.
+
 config EHEA
        tristate "eHEA Ethernet support"
        depends on IBMEBUS
@@ -2488,6 +2493,13 @@ config NETXEN_NIC
        help
          This enables the support for NetXen's Gigabit Ethernet card.
 
+config PASEMI_MAC
+       tristate "PA Semi 1/10Gbit MAC"
+       depends on PPC64 && PCI
+       help
+         This driver supports the on-chip 1/10Gbit Ethernet controller on
+         PA Semi's PWRficient line of chips.
+
 endmenu
 
 source "drivers/net/tokenring/Kconfig"
@@ -2541,6 +2553,7 @@ config DEFXX
 config SKFP
        tristate "SysKonnect FDDI PCI support"
        depends on FDDI && PCI
+       select BITREVERSE
        ---help---
          Say Y here if you have a SysKonnect FDDI PCI adapter.
          The following adapters are supported by this driver:
index 4c0d4e5..0878e3d 100644 (file)
@@ -6,6 +6,7 @@ obj-$(CONFIG_E1000) += e1000/
 obj-$(CONFIG_IBM_EMAC) += ibm_emac/
 obj-$(CONFIG_IXGB) += ixgb/
 obj-$(CONFIG_CHELSIO_T1) += chelsio/
+obj-$(CONFIG_CHELSIO_T3) += cxgb3/
 obj-$(CONFIG_EHEA) += ehea/
 obj-$(CONFIG_BONDING) += bonding/
 obj-$(CONFIG_GIANFAR) += gianfar_driver.o
@@ -36,8 +37,6 @@ obj-$(CONFIG_CASSINI) += cassini.o
 obj-$(CONFIG_MACE) += mace.o
 obj-$(CONFIG_BMAC) += bmac.o
 
-obj-$(CONFIG_OAKNET) += oaknet.o 8390.o
-
 obj-$(CONFIG_DGRS) += dgrs.o
 obj-$(CONFIG_VORTEX) += 3c59x.o
 obj-$(CONFIG_TYPHOON) += typhoon.o
@@ -137,7 +136,6 @@ obj-$(CONFIG_AT1700) += at1700.o
 obj-$(CONFIG_EL1) += 3c501.o
 obj-$(CONFIG_EL16) += 3c507.o
 obj-$(CONFIG_ELMC) += 3c523.o
-obj-$(CONFIG_SKMC) += sk_mca.o
 obj-$(CONFIG_IBMLANA) += ibmlana.o
 obj-$(CONFIG_ELMC_II) += 3c527.o
 obj-$(CONFIG_EL3) += 3c509.o
@@ -160,6 +158,7 @@ obj-$(CONFIG_APRICOT) += 82596.o
 obj-$(CONFIG_LASI_82596) += lasi_82596.o
 obj-$(CONFIG_MVME16x_NET) += 82596.o
 obj-$(CONFIG_BVME6000_NET) += 82596.o
+obj-$(CONFIG_SC92031) += sc92031.o
 
 # This is also a 82596 and should probably be merged
 obj-$(CONFIG_LP486E) += lp486e.o
@@ -196,6 +195,7 @@ obj-$(CONFIG_SMC91X) += smc91x.o
 obj-$(CONFIG_SMC911X) += smc911x.o
 obj-$(CONFIG_DM9000) += dm9000.o
 obj-$(CONFIG_FEC_8XX) += fec_8xx/
+obj-$(CONFIG_PASEMI_MAC) += pasemi_mac.o
 
 obj-$(CONFIG_MACB) += macb.o
 
index 9305eb9..dd8ed45 100644 (file)
@@ -59,7 +59,6 @@ extern struct net_device *wavelan_probe(int unit);
 extern struct net_device *arlan_probe(int unit);
 extern struct net_device *el16_probe(int unit);
 extern struct net_device *elmc_probe(int unit);
-extern struct net_device *skmca_probe(int unit);
 extern struct net_device *elplus_probe(int unit);
 extern struct net_device *ac3200_probe(int unit);
 extern struct net_device *es_probe(int unit);
@@ -152,9 +151,6 @@ static struct devprobe2 mca_probes[] __initdata = {
 #endif
 #ifdef CONFIG_ELMC_II          /* 3c527 */
        {mc32_probe, 0},
-#endif
-#ifdef CONFIG_SKMC              /* SKnet Microchannel */
-        {skmca_probe, 0},
 #endif
        {NULL, 0},
 };
index 18896f2..9c399aa 100644 (file)
@@ -1334,8 +1334,7 @@ err_no_interrupt:
 static void amd8111e_poll(struct net_device *dev)
 {
        unsigned long flags;
-       local_save_flags(flags);
-       local_irq_disable();
+       local_irq_save(flags);
        amd8111e_interrupt(0, dev);
        local_irq_restore(flags);
 }
index fada15d..1621b8f 100644 (file)
@@ -641,7 +641,7 @@ static void at91ether_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo
 {
        strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
        strlcpy(info->version, DRV_VERSION, sizeof(info->version));
-       strlcpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+       strlcpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
 }
 
 static const struct ethtool_ops at91ether_ethtool_ops = {
index f3faa4f..72c41f5 100644 (file)
@@ -587,7 +587,7 @@ static void etherh_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i
 {
        strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
        strlcpy(info->version, DRV_VERSION, sizeof(info->version));
-       strlcpy(info->bus_info, dev->class_dev.dev->bus_id,
+       strlcpy(info->bus_info, dev->dev.parent->bus_id,
                sizeof(info->bus_info));
 }
 
index 303a8d9..5ff7882 100644 (file)
@@ -721,7 +721,7 @@ static void b44_recycle_rx(struct b44 *bp, int src_idx, u32 dest_idx_unmasked)
        struct ring_info *src_map, *dest_map;
        struct rx_header *rh;
        int dest_idx;
-       u32 ctrl;
+       __le32 ctrl;
 
        dest_idx = dest_idx_unmasked & (B44_RX_RING_SIZE - 1);
        dest_desc = &bp->rx_ring[dest_idx];
@@ -783,7 +783,7 @@ static int b44_rx(struct b44 *bp, int budget)
                                            RX_PKT_BUF_SZ,
                                            PCI_DMA_FROMDEVICE);
                rh = (struct rx_header *) skb->data;
-               len = cpu_to_le16(rh->len);
+               len = le16_to_cpu(rh->len);
                if ((len > (RX_PKT_BUF_SZ - bp->rx_offset)) ||
                    (rh->flags & cpu_to_le16(RX_FLAG_ERRORS))) {
                drop_it:
@@ -799,7 +799,7 @@ static int b44_rx(struct b44 *bp, int budget)
                        do {
                                udelay(2);
                                barrier();
-                               len = cpu_to_le16(rh->len);
+                               len = le16_to_cpu(rh->len);
                        } while (len == 0 && i++ < 5);
                        if (len == 0)
                                goto drop_it;
@@ -2061,7 +2061,7 @@ out:
 static int b44_read_eeprom(struct b44 *bp, u8 *data)
 {
        long i;
-       u16 *ptr = (u16 *) data;
+       __le16 *ptr = (__le16 *) data;
 
        for (i = 0; i < 128; i += 2)
                ptr[i / 2] = cpu_to_le16(readw(bp->regs + 4096 + i));
index 4944507..18fc133 100644 (file)
 #define  MII_TLEDCTRL_ENABLE   0x0040
 
 struct dma_desc {
-       u32     ctrl;
-       u32     addr;
+       __le32  ctrl;
+       __le32  addr;
 };
 
 /* There are only 12 bits in the DMA engine for descriptor offsetting
@@ -327,9 +327,9 @@ struct dma_desc {
 #define RX_COPY_THRESHOLD      256
 
 struct rx_header {
-       u16     len;
-       u16     flags;
-       u16     pad[12];
+       __le16  len;
+       __le16  flags;
+       __le16  pad[12];
 };
 #define RX_HEADER_LEN  28
 
index 4528ce9..c143304 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/spinlock.h>
 #include <linux/crc32.h>
+#include <linux/bitrev.h>
 #include <asm/prom.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
@@ -140,7 +141,6 @@ static unsigned char *bmac_emergency_rxbuf;
        + (N_RX_RING + N_TX_RING + 4) * sizeof(struct dbdma_cmd) \
        + sizeof(struct sk_buff_head))
 
-static unsigned char bitrev(unsigned char b);
 static int bmac_open(struct net_device *dev);
 static int bmac_close(struct net_device *dev);
 static int bmac_transmit_packet(struct sk_buff *skb, struct net_device *dev);
@@ -586,18 +586,6 @@ bmac_construct_rxbuff(struct sk_buff *skb, volatile struct dbdma_cmd *cp)
                     virt_to_bus(addr), 0);
 }
 
-/* Bit-reverse one byte of an ethernet hardware address. */
-static unsigned char
-bitrev(unsigned char b)
-{
-       int d = 0, i;
-
-       for (i = 0; i < 8; ++i, b >>= 1)
-               d = (d << 1) | (b & 1);
-       return d;
-}
-
-
 static void
 bmac_init_tx_ring(struct bmac_data *bp)
 {
@@ -1224,8 +1212,8 @@ bmac_get_station_address(struct net_device *dev, unsigned char *ea)
                {
                        reset_and_select_srom(dev);
                        data = read_srom(dev, i + EnetAddressOffset/2, SROMAddressBits);
-                       ea[2*i]   = bitrev(data & 0x0ff);
-                       ea[2*i+1] = bitrev((data >> 8) & 0x0ff);
+                       ea[2*i]   = bitrev8(data & 0x0ff);
+                       ea[2*i+1] = bitrev8((data >> 8) & 0x0ff);
                }
 }
 
@@ -1315,7 +1303,7 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i
 
        rev = addr[0] == 0 && addr[1] == 0xA0;
        for (j = 0; j < 6; ++j)
-               dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+               dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j];
 
        /* Enable chip without interrupts for now */
        bmac_enable_and_reset_chip(dev);
index ee7b75b..5a96d76 100644 (file)
 #include <linux/if_vlan.h>
 #define BCM_VLAN 1
 #endif
-#ifdef NETIF_F_TSO
 #include <net/ip.h>
 #include <net/tcp.h>
 #include <net/checksum.h>
-#define BCM_TSO 1
-#endif
 #include <linux/workqueue.h>
 #include <linux/crc32.h>
 #include <linux/prefetch.h>
@@ -1728,7 +1725,7 @@ bnx2_tx_int(struct bnx2 *bp)
 
                tx_buf = &bp->tx_buf_ring[sw_ring_cons];
                skb = tx_buf->skb;
-#ifdef BCM_TSO
+
                /* partial BD completions possible with TSO packets */
                if (skb_is_gso(skb)) {
                        u16 last_idx, last_ring_idx;
@@ -1744,7 +1741,7 @@ bnx2_tx_int(struct bnx2 *bp)
                                break;
                        }
                }
-#endif
+
                pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
                        skb_headlen(skb), PCI_DMA_TODEVICE);
 
@@ -4514,7 +4511,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
                vlan_tag_flags |=
                        (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
        }
-#ifdef BCM_TSO
        if ((mss = skb_shinfo(skb)->gso_size) &&
                (skb->len > (bp->dev->mtu + ETH_HLEN))) {
                u32 tcp_opt_len, ip_tcp_len;
@@ -4547,7 +4543,6 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
                }
        }
        else
-#endif
        {
                mss = 0;
        }
@@ -5544,10 +5539,8 @@ static const struct ethtool_ops bnx2_ethtool_ops = {
        .set_tx_csum            = ethtool_op_set_tx_csum,
        .get_sg                 = ethtool_op_get_sg,
        .set_sg                 = ethtool_op_set_sg,
-#ifdef BCM_TSO
        .get_tso                = ethtool_op_get_tso,
        .set_tso                = bnx2_set_tso,
-#endif
        .self_test_count        = bnx2_self_test_count,
        .self_test              = bnx2_self_test,
        .get_strings            = bnx2_get_strings,
@@ -5954,8 +5947,7 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
         * responding after a while.
         *
         * AMD believes this incompatibility is unique to the 5706, and
-        * prefers to locally disable MSI rather than globally disabling it
-        * using pci_msi_quirk.
+        * prefers to locally disable MSI rather than globally disabling it.
         */
        if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
                struct pci_dev *amd_8132 = NULL;
@@ -6104,9 +6096,7 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
 #ifdef BCM_VLAN
        dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
 #endif
-#ifdef BCM_TSO
        dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
-#endif
 
        netif_carrier_off(bp->dev);
 
index 6482aed..d3801a0 100644 (file)
@@ -4704,6 +4704,7 @@ static int bond_check_params(struct bond_params *params)
 static struct lock_class_key bonding_netdev_xmit_lock_key;
 
 /* Create a new bond based on the specified name and bonding parameters.
+ * If name is NULL, obtain a suitable "bond%d" name for us.
  * Caller must NOT hold rtnl_lock; we need to release it here before we
  * set up our sysfs entries.
  */
@@ -4713,7 +4714,8 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
        int res;
 
        rtnl_lock();
-       bond_dev = alloc_netdev(sizeof(struct bonding), name, ether_setup);
+       bond_dev = alloc_netdev(sizeof(struct bonding), name ? name : "",
+                               ether_setup);
        if (!bond_dev) {
                printk(KERN_ERR DRV_NAME
                       ": %s: eek! can't alloc netdev!\n",
@@ -4722,6 +4724,12 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
                goto out_rtnl;
        }
 
+       if (!name) {
+               res = dev_alloc_name(bond_dev, "bond%d");
+               if (res < 0)
+                       goto out_netdev;
+       }
+
        /* bond_init() must be called after dev_alloc_name() (for the
         * /proc files), but before register_netdevice(), because we
         * need to set function pointers.
@@ -4748,14 +4756,19 @@ int bond_create(char *name, struct bond_params *params, struct bonding **newbond
 
        rtnl_unlock(); /* allows sysfs registration of net device */
        res = bond_create_sysfs_entry(bond_dev->priv);
-       goto done;
+       if (res < 0) {
+               rtnl_lock();
+               goto out_bond;
+       }
+
+       return 0;
+
 out_bond:
        bond_deinit(bond_dev);
 out_netdev:
        free_netdev(bond_dev);
 out_rtnl:
        rtnl_unlock();
-done:
        return res;
 }
 
@@ -4763,7 +4776,6 @@ static int __init bonding_init(void)
 {
        int i;
        int res;
-       char new_bond_name[8];  /* Enough room for 999 bonds at init. */
 
        printk(KERN_INFO "%s", version);
 
@@ -4776,8 +4788,7 @@ static int __init bonding_init(void)
        bond_create_proc_dir();
 #endif
        for (i = 0; i < max_bonds; i++) {
-               sprintf(new_bond_name, "bond%d",i);
-               res = bond_create(new_bond_name,&bonding_defaults, NULL);
+               res = bond_create(NULL, &bonding_defaults, NULL);
                if (res)
                        goto err;
        }
index ced9ed8..878f7aa 100644 (file)
@@ -39,8 +39,7 @@
 
 /* #define BONDING_DEBUG 1 */
 #include "bonding.h"
-#define to_class_dev(obj) container_of(obj,struct class_device,kobj)
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
+#define to_dev(obj)    container_of(obj,struct device,kobj)
 #define to_bond(cd)    ((struct bonding *)(to_net_dev(cd)->priv))
 
 /*---------------------------- Declarations -------------------------------*/
@@ -154,7 +153,7 @@ static ssize_t bonding_store_bonds(struct class *cls, const char *buffer, size_t
                                 * If it's > expected, then there's a file open,
                                 * and we have to fail.
                                 */
-                               if (atomic_read(&bond->dev->class_dev.kobj.kref.refcount)
+                               if (atomic_read(&bond->dev->dev.kobj.kref.refcount)
                                                        > expected_refcount){
                                        rtnl_unlock();
                                        printk(KERN_INFO DRV_NAME
@@ -201,13 +200,13 @@ int bond_create_slave_symlinks(struct net_device *master, struct net_device *sla
        int ret = 0;
 
        /* first, create a link from the slave back to the master */
-       ret = sysfs_create_link(&(slave->class_dev.kobj), &(master->class_dev.kobj),
+       ret = sysfs_create_link(&(slave->dev.kobj), &(master->dev.kobj),
                                "master");
        if (ret)
                return ret;
        /* next, create a link from the master to the slave */
        sprintf(linkname,"slave_%s",slave->name);
-       ret = sysfs_create_link(&(master->class_dev.kobj), &(slave->class_dev.kobj),
+       ret = sysfs_create_link(&(master->dev.kobj), &(slave->dev.kobj),
                                linkname);
        return ret;
 
@@ -217,20 +216,21 @@ void bond_destroy_slave_symlinks(struct net_device *master, struct net_device *s
 {
        char linkname[IFNAMSIZ+7];
 
-       sysfs_remove_link(&(slave->class_dev.kobj), "master");
+       sysfs_remove_link(&(slave->dev.kobj), "master");
        sprintf(linkname,"slave_%s",slave->name);
-       sysfs_remove_link(&(master->class_dev.kobj), linkname);
+       sysfs_remove_link(&(master->dev.kobj), linkname);
 }
 
 
 /*
  * Show the slaves in the current bond.
  */
-static ssize_t bonding_show_slaves(struct class_device *cd, char *buf)
+static ssize_t bonding_show_slaves(struct device *d,
+                                  struct device_attribute *attr, char *buf)
 {
        struct slave *slave;
        int i, res = 0;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        read_lock_bh(&bond->lock);
        bond_for_each_slave(bond, slave, i) {
@@ -254,14 +254,16 @@ static ssize_t bonding_show_slaves(struct class_device *cd, char *buf)
  * up for this to succeed.
  * This function is largely the same flow as bonding_update_bonds().
  */
-static ssize_t bonding_store_slaves(struct class_device *cd, const char *buffer, size_t count)
+static ssize_t bonding_store_slaves(struct device *d,
+                                   struct device_attribute *attr,
+                                   const char *buffer, size_t count)
 {
        char command[IFNAMSIZ + 1] = { 0, };
        char *ifname;
        int i, res, found, ret = count;
        struct slave *slave;
        struct net_device *dev = NULL;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        /* Quick sanity check -- is the bond interface up? */
        if (!(bond->dev->flags & IFF_UP)) {
@@ -387,25 +389,28 @@ out:
        return ret;
 }
 
-static CLASS_DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves);
+static DEVICE_ATTR(slaves, S_IRUGO | S_IWUSR, bonding_show_slaves, bonding_store_slaves);
 
 /*
  * Show and set the bonding mode.  The bond interface must be down to
  * change the mode.
  */
-static ssize_t bonding_show_mode(struct class_device *cd, char *buf)
+static ssize_t bonding_show_mode(struct device *d,
+                                struct device_attribute *attr, char *buf)
 {
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        return sprintf(buf, "%s %d\n",
                        bond_mode_tbl[bond->params.mode].modename,
                        bond->params.mode) + 1;
 }
 
-static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_mode(struct device *d,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
 {
        int new_value, ret = count;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if (bond->dev->flags & IFF_UP) {
                printk(KERN_ERR DRV_NAME
@@ -438,16 +443,18 @@ static ssize_t bonding_store_mode(struct class_device *cd, const char *buf, size
 out:
        return ret;
 }
-static CLASS_DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode);
+static DEVICE_ATTR(mode, S_IRUGO | S_IWUSR, bonding_show_mode, bonding_store_mode);
 
 /*
  * Show and set the bonding transmit hash method.  The bond interface must be down to
  * change the xmit hash policy.
  */
-static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf)
+static ssize_t bonding_show_xmit_hash(struct device *d,
+                                     struct device_attribute *attr,
+                                     char *buf)
 {
        int count;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if ((bond->params.mode != BOND_MODE_XOR) &&
            (bond->params.mode != BOND_MODE_8023AD)) {
@@ -462,10 +469,12 @@ static ssize_t bonding_show_xmit_hash(struct class_device *cd, char *buf)
        return count;
 }
 
-static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_xmit_hash(struct device *d,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count)
 {
        int new_value, ret = count;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if (bond->dev->flags & IFF_UP) {
                printk(KERN_ERR DRV_NAME
@@ -501,24 +510,28 @@ static ssize_t bonding_store_xmit_hash(struct class_device *cd, const char *buf,
 out:
        return ret;
 }
-static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
+static DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
 
 /*
  * Show and set arp_validate.
  */
-static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_validate(struct device *d,
+                                        struct device_attribute *attr,
+                                        char *buf)
 {
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        return sprintf(buf, "%s %d\n",
                       arp_validate_tbl[bond->params.arp_validate].modename,
                       bond->params.arp_validate) + 1;
 }
 
-static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_validate(struct device *d,
+                                         struct device_attribute *attr,
+                                         const char *buf, size_t count)
 {
        int new_value;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        new_value = bond_parse_parm((char *)buf, arp_validate_tbl);
        if (new_value < 0) {
@@ -548,7 +561,7 @@ static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *b
        return count;
 }
 
-static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
+static DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
 
 /*
  * Show and set the arp timer interval.  There are two tricky bits
@@ -556,17 +569,21 @@ static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_valid
  * MII monitoring.  Second, if the ARP timer isn't running, we must
  * start it.
  */
-static ssize_t bonding_show_arp_interval(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_interval(struct device *d,
+                                        struct device_attribute *attr,
+                                        char *buf)
 {
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        return sprintf(buf, "%d\n", bond->params.arp_interval) + 1;
 }
 
-static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_interval(struct device *d,
+                                         struct device_attribute *attr,
+                                         const char *buf, size_t count)
 {
        int new_value, ret = count;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if (sscanf(buf, "%d", &new_value) != 1) {
                printk(KERN_ERR DRV_NAME
@@ -638,15 +655,17 @@ static ssize_t bonding_store_arp_interval(struct class_device *cd, const char *b
 out:
        return ret;
 }
-static CLASS_DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval);
+static DEVICE_ATTR(arp_interval, S_IRUGO | S_IWUSR , bonding_show_arp_interval, bonding_store_arp_interval);
 
 /*
  * Show and set the arp targets.
  */
-static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf)
+static ssize_t bonding_show_arp_targets(struct device *d,
+                                       struct device_attribute *attr,
+                                       char *buf)
 {
        int i, res = 0;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
                if (bond->params.arp_targets[i])
@@ -660,11 +679,13 @@ static ssize_t bonding_show_arp_targets(struct class_device *cd, char *buf)
        return res;
 }
 
-static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_arp_targets(struct device *d,
+                                        struct device_attribute *attr,
+                                        const char *buf, size_t count)
 {
        u32 newtarget;
        int i = 0, done = 0, ret = count;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
        u32 *targets;
 
        targets = bond->params.arp_targets;
@@ -742,24 +763,28 @@ static ssize_t bonding_store_arp_targets(struct class_device *cd, const char *bu
 out:
        return ret;
 }
-static CLASS_DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
+static DEVICE_ATTR(arp_ip_target, S_IRUGO | S_IWUSR , bonding_show_arp_targets, bonding_store_arp_targets);
 
 /*
  * Show and set the up and down delays.  These must be multiples of the
  * MII monitoring value, and are stored internally as the multiplier.
  * Thus, we must translate to MS for the real world.
  */
-static ssize_t bonding_show_downdelay(struct class_device *cd, char *buf)
+static ssize_t bonding_show_downdelay(struct device *d,
+                                     struct device_attribute *attr,
+                                     char *buf)
 {
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        return sprintf(buf, "%d\n", bond->params.downdelay * bond->params.miimon) + 1;
 }
 
-static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_downdelay(struct device *d,
+                                      struct device_attribute *attr,
+                                      const char *buf, size_t count)
 {
        int new_value, ret = count;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if (!(bond->params.miimon)) {
                printk(KERN_ERR DRV_NAME
@@ -800,20 +825,24 @@ static ssize_t bonding_store_downdelay(struct class_device *cd, const char *buf,
 out:
        return ret;
 }
-static CLASS_DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay);
+static DEVICE_ATTR(downdelay, S_IRUGO | S_IWUSR , bonding_show_downdelay, bonding_store_downdelay);
 
-static ssize_t bonding_show_updelay(struct class_device *cd, char *buf)
+static ssize_t bonding_show_updelay(struct device *d,
+                                   struct device_attribute *attr,
+                                   char *buf)
 {
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        return sprintf(buf, "%d\n", bond->params.updelay * bond->params.miimon) + 1;
 
 }
 
-static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_updelay(struct device *d,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
 {
        int new_value, ret = count;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if (!(bond->params.miimon)) {
                printk(KERN_ERR DRV_NAME
@@ -854,25 +883,29 @@ static ssize_t bonding_store_updelay(struct class_device *cd, const char *buf, s
 out:
        return ret;
 }
-static CLASS_DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay);
+static DEVICE_ATTR(updelay, S_IRUGO | S_IWUSR , bonding_show_updelay, bonding_store_updelay);
 
 /*
  * Show and set the LACP interval.  Interface must be down, and the mode
  * must be set to 802.3ad mode.
  */
-static ssize_t bonding_show_lacp(struct class_device *cd, char *buf)
+static ssize_t bonding_show_lacp(struct device *d,
+                                struct device_attribute *attr,
+                                char *buf)
 {
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        return sprintf(buf, "%s %d\n",
                bond_lacp_tbl[bond->params.lacp_fast].modename,
                bond->params.lacp_fast) + 1;
 }
 
-static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_lacp(struct device *d,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
 {
        int new_value, ret = count;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if (bond->dev->flags & IFF_UP) {
                printk(KERN_ERR DRV_NAME
@@ -906,7 +939,7 @@ static ssize_t bonding_store_lacp(struct class_device *cd, const char *buf, size
 out:
        return ret;
 }
-static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
+static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp);
 
 /*
  * Show and set the MII monitor interval.  There are two tricky bits
@@ -914,17 +947,21 @@ static CLASS_DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bondin
  * ARP monitoring.  Second, if the timer isn't running, we must
  * start it.
  */
-static ssize_t bonding_show_miimon(struct class_device *cd, char *buf)
+static ssize_t bonding_show_miimon(struct device *d,
+                                  struct device_attribute *attr,
+                                  char *buf)
 {
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        return sprintf(buf, "%d\n", bond->params.miimon) + 1;
 }
 
-static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_miimon(struct device *d,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
 {
        int new_value, ret = count;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if (sscanf(buf, "%d", &new_value) != 1) {
                printk(KERN_ERR DRV_NAME
@@ -1000,7 +1037,7 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si
 out:
        return ret;
 }
-static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon);
+static DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding_store_miimon);
 
 /*
  * Show and set the primary slave.  The store function is much
@@ -1009,10 +1046,12 @@ static CLASS_DEVICE_ATTR(miimon, S_IRUGO | S_IWUSR, bonding_show_miimon, bonding
  * The bond must be a mode that supports a primary for this be
  * set.
  */
-static ssize_t bonding_show_primary(struct class_device *cd, char *buf)
+static ssize_t bonding_show_primary(struct device *d,
+                                   struct device_attribute *attr,
+                                   char *buf)
 {
        int count = 0;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if (bond->primary_slave)
                count = sprintf(buf, "%s\n", bond->primary_slave->dev->name) + 1;
@@ -1022,11 +1061,13 @@ static ssize_t bonding_show_primary(struct class_device *cd, char *buf)
        return count;
 }
 
-static ssize_t bonding_store_primary(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_primary(struct device *d,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
 {
        int i;
        struct slave *slave;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        write_lock_bh(&bond->lock);
        if (!USES_PRIMARY(bond->params.mode)) {
@@ -1065,22 +1106,26 @@ out:
        write_unlock_bh(&bond->lock);
        return count;
 }
-static CLASS_DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary);
+static DEVICE_ATTR(primary, S_IRUGO | S_IWUSR, bonding_show_primary, bonding_store_primary);
 
 /*
  * Show and set the use_carrier flag.
  */
-static ssize_t bonding_show_carrier(struct class_device *cd, char *buf)
+static ssize_t bonding_show_carrier(struct device *d,
+                                   struct device_attribute *attr,
+                                   char *buf)
 {
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        return sprintf(buf, "%d\n", bond->params.use_carrier) + 1;
 }
 
-static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_carrier(struct device *d,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
 {
        int new_value, ret = count;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
 
        if (sscanf(buf, "%d", &new_value) != 1) {
@@ -1102,16 +1147,18 @@ static ssize_t bonding_store_carrier(struct class_device *cd, const char *buf, s
 out:
        return count;
 }
-static CLASS_DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier);
+static DEVICE_ATTR(use_carrier, S_IRUGO | S_IWUSR, bonding_show_carrier, bonding_store_carrier);
 
 
 /*
  * Show and set currently active_slave.
  */
-static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf)
+static ssize_t bonding_show_active_slave(struct device *d,
+                                        struct device_attribute *attr,
+                                        char *buf)
 {
        struct slave *curr;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
        int count;
 
 
@@ -1126,13 +1173,15 @@ static ssize_t bonding_show_active_slave(struct class_device *cd, char *buf)
        return count;
 }
 
-static ssize_t bonding_store_active_slave(struct class_device *cd, const char *buf, size_t count)
+static ssize_t bonding_store_active_slave(struct device *d,
+                                         struct device_attribute *attr,
+                                         const char *buf, size_t count)
 {
        int i;
        struct slave *slave;
         struct slave *old_active = NULL;
         struct slave *new_active = NULL;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        write_lock_bh(&bond->lock);
        if (!USES_PRIMARY(bond->params.mode)) {
@@ -1194,16 +1243,18 @@ out:
        return count;
 
 }
-static CLASS_DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave);
+static DEVICE_ATTR(active_slave, S_IRUGO | S_IWUSR, bonding_show_active_slave, bonding_store_active_slave);
 
 
 /*
  * Show link status of the bond interface.
  */
-static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf)
+static ssize_t bonding_show_mii_status(struct device *d,
+                                      struct device_attribute *attr,
+                                      char *buf)
 {
        struct slave *curr;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        read_lock(&bond->curr_slave_lock);
        curr = bond->curr_active_slave;
@@ -1211,16 +1262,18 @@ static ssize_t bonding_show_mii_status(struct class_device *cd, char *buf)
 
        return sprintf(buf, "%s\n", (curr) ? "up" : "down") + 1;
 }
-static CLASS_DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
+static DEVICE_ATTR(mii_status, S_IRUGO, bonding_show_mii_status, NULL);
 
 
 /*
  * Show current 802.3ad aggregator ID.
  */
-static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_aggregator(struct device *d,
+                                         struct device_attribute *attr,
+                                         char *buf)
 {
        int count = 0;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if (bond->params.mode == BOND_MODE_8023AD) {
                struct ad_info ad_info;
@@ -1231,16 +1284,18 @@ static ssize_t bonding_show_ad_aggregator(struct class_device *cd, char *buf)
 
        return count;
 }
-static CLASS_DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL);
+static DEVICE_ATTR(ad_aggregator, S_IRUGO, bonding_show_ad_aggregator, NULL);
 
 
 /*
  * Show number of active 802.3ad ports.
  */
-static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_num_ports(struct device *d,
+                                        struct device_attribute *attr,
+                                        char *buf)
 {
        int count = 0;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if (bond->params.mode == BOND_MODE_8023AD) {
                struct ad_info ad_info;
@@ -1251,16 +1306,18 @@ static ssize_t bonding_show_ad_num_ports(struct class_device *cd, char *buf)
 
        return count;
 }
-static CLASS_DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL);
+static DEVICE_ATTR(ad_num_ports, S_IRUGO, bonding_show_ad_num_ports, NULL);
 
 
 /*
  * Show current 802.3ad actor key.
  */
-static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_actor_key(struct device *d,
+                                        struct device_attribute *attr,
+                                        char *buf)
 {
        int count = 0;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if (bond->params.mode == BOND_MODE_8023AD) {
                struct ad_info ad_info;
@@ -1271,16 +1328,18 @@ static ssize_t bonding_show_ad_actor_key(struct class_device *cd, char *buf)
 
        return count;
 }
-static CLASS_DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL);
+static DEVICE_ATTR(ad_actor_key, S_IRUGO, bonding_show_ad_actor_key, NULL);
 
 
 /*
  * Show current 802.3ad partner key.
  */
-static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_partner_key(struct device *d,
+                                          struct device_attribute *attr,
+                                          char *buf)
 {
        int count = 0;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if (bond->params.mode == BOND_MODE_8023AD) {
                struct ad_info ad_info;
@@ -1291,16 +1350,18 @@ static ssize_t bonding_show_ad_partner_key(struct class_device *cd, char *buf)
 
        return count;
 }
-static CLASS_DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL);
+static DEVICE_ATTR(ad_partner_key, S_IRUGO, bonding_show_ad_partner_key, NULL);
 
 
 /*
  * Show current 802.3ad partner mac.
  */
-static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf)
+static ssize_t bonding_show_ad_partner_mac(struct device *d,
+                                          struct device_attribute *attr,
+                                          char *buf)
 {
        int count = 0;
-       struct bonding *bond = to_bond(cd);
+       struct bonding *bond = to_bond(d);
 
        if (bond->params.mode == BOND_MODE_8023AD) {
                struct ad_info ad_info;
@@ -1319,30 +1380,30 @@ static ssize_t bonding_show_ad_partner_mac(struct class_device *cd, char *buf)
 
        return count;
 }
-static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
+static DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, NULL);
 
 
 
 static struct attribute *per_bond_attrs[] = {
-       &class_device_attr_slaves.attr,
-       &class_device_attr_mode.attr,
-       &class_device_attr_arp_validate.attr,
-       &class_device_attr_arp_interval.attr,
-       &class_device_attr_arp_ip_target.attr,
-       &class_device_attr_downdelay.attr,
-       &class_device_attr_updelay.attr,
-       &class_device_attr_lacp_rate.attr,
-       &class_device_attr_xmit_hash_policy.attr,
-       &class_device_attr_miimon.attr,
-       &class_device_attr_primary.attr,
-       &class_device_attr_use_carrier.attr,
-       &class_device_attr_active_slave.attr,
-       &class_device_attr_mii_status.attr,
-       &class_device_attr_ad_aggregator.attr,
-       &class_device_attr_ad_num_ports.attr,
-       &class_device_attr_ad_actor_key.attr,
-       &class_device_attr_ad_partner_key.attr,
-       &class_device_attr_ad_partner_mac.attr,
+       &dev_attr_slaves.attr,
+       &dev_attr_mode.attr,
+       &dev_attr_arp_validate.attr,
+       &dev_attr_arp_interval.attr,
+       &dev_attr_arp_ip_target.attr,
+       &dev_attr_downdelay.attr,
+       &dev_attr_updelay.attr,
+       &dev_attr_lacp_rate.attr,
+       &dev_attr_xmit_hash_policy.attr,
+       &dev_attr_miimon.attr,
+       &dev_attr_primary.attr,
+       &dev_attr_use_carrier.attr,
+       &dev_attr_active_slave.attr,
+       &dev_attr_mii_status.attr,
+       &dev_attr_ad_aggregator.attr,
+       &dev_attr_ad_num_ports.attr,
+       &dev_attr_ad_actor_key.attr,
+       &dev_attr_ad_partner_key.attr,
+       &dev_attr_ad_partner_mac.attr,
        NULL,
 };
 
@@ -1367,11 +1428,26 @@ int bond_create_sysfs(void)
        if (!firstbond)
                return -ENODEV;
 
-       netdev_class = firstbond->dev->class_dev.class;
+       netdev_class = firstbond->dev->dev.class;
        if (!netdev_class)
                return -ENODEV;
 
        ret = class_create_file(netdev_class, &class_attr_bonding_masters);
+       /*
+        * Permit multiple loads of the module by ignoring failures to
+        * create the bonding_masters sysfs file.  Bonding devices
+        * created by second or subsequent loads of the module will
+        * not be listed in, or controllable by, bonding_masters, but
+        * will have the usual "bonding" sysfs directory.
+        *
+        * This is done to preserve backwards compatibility for
+        * initscripts/sysconfig, which load bonding multiple times to
+        * configure multiple bonding devices.
+        */
+       if (ret == -EEXIST) {
+               netdev_class = NULL;
+               return 0;
+       }
 
        return ret;
 
@@ -1395,13 +1471,13 @@ int bond_create_sysfs_entry(struct bonding *bond)
        struct net_device *dev = bond->dev;
        int err;
 
-       err = sysfs_create_group(&(dev->class_dev.kobj), &bonding_group);
+       err = sysfs_create_group(&(dev->dev.kobj), &bonding_group);
        if (err) {
                printk(KERN_EMERG "eek! didn't create group!\n");
        }
 
        if (expected_refcount < 1)
-               expected_refcount = atomic_read(&bond->dev->class_dev.kobj.kref.refcount);
+               expected_refcount = atomic_read(&bond->dev->dev.kobj.kref.refcount);
 
        return err;
 }
@@ -1412,6 +1488,6 @@ void bond_destroy_sysfs_entry(struct bonding *bond)
 {
        struct net_device *dev = bond->dev;
 
-       sysfs_remove_group(&(dev->class_dev.kobj), &bonding_group);
+       sysfs_remove_group(&(dev->dev.kobj), &bonding_group);
 }
 
index 0978c9a..41aa78b 100644 (file)
@@ -22,8 +22,8 @@
 #include "bond_3ad.h"
 #include "bond_alb.h"
 
-#define DRV_VERSION    "3.1.1"
-#define DRV_RELDATE    "September 26, 2006"
+#define DRV_VERSION    "3.1.2"
+#define DRV_RELDATE    "January 20, 2007"
 #define DRV_NAME       "bonding"
 #define DRV_DESCRIPTION        "Ethernet Channel Bonding Driver"
 
@@ -237,12 +237,13 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
 #define BOND_ARP_VALIDATE_ALL          (BOND_ARP_VALIDATE_ACTIVE | \
                                         BOND_ARP_VALIDATE_BACKUP)
 
-extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave)
+static inline int slave_do_arp_validate(struct bonding *bond,
+                                       struct slave *slave)
 {
        return bond->params.arp_validate & (1 << slave->state);
 }
 
-extern inline unsigned long slave_last_rx(struct bonding *bond,
+static inline unsigned long slave_last_rx(struct bonding *bond,
                                        struct slave *slave)
 {
        if (slave_do_arp_validate(bond, slave))
index 74758d2..787f2f2 100644 (file)
@@ -324,7 +324,7 @@ struct board_info {
        unsigned char           mdio_phybaseaddr;
        struct gmac            *gmac;
        struct gphy            *gphy;
-       struct mdio_ops        *mdio_ops;
+       struct mdio_ops        *mdio_ops;
        const char             *desc;
 };
 
index 35f565b..e36d45b 100644 (file)
@@ -103,7 +103,7 @@ enum CPL_opcode {
        CPL_MIGRATE_C2T_RPL   = 0xDD,
        CPL_ERROR             = 0xD7,
 
-    /* internal: driver -> TOM */
+       /* internal: driver -> TOM */
        CPL_MSS_CHANGE        = 0xE1
 };
 
@@ -159,8 +159,8 @@ enum {                // TX_PKT_LSO ethernet types
 };
 
 union opcode_tid {
-    u32 opcode_tid;
-    u8 opcode;
+       u32 opcode_tid;
+       u8 opcode;
 };
 
 #define S_OPCODE 24
@@ -234,7 +234,7 @@ struct cpl_pass_accept_req {
        u32 local_ip;
        u32 peer_ip;
        u32 tos_tid;
-    struct tcp_options tcp_options;
+       struct tcp_options tcp_options;
        u8  dst_mac[6];
        u16 vlan_tag;
        u8  src_mac[6];
@@ -250,12 +250,12 @@ struct cpl_pass_accept_rpl {
        u32 peer_ip;
        u32 opt0h;
        union {
-       u32 opt0l;
-       struct {
-           u8 rsvd[3];
-           u8 status;
+               u32 opt0l;
+               struct {
+                   u8 rsvd[3];
+                   u8 status;
+               };
        };
-    };
 };
 
 struct cpl_act_open_req {
index fd5d821..7d0f24f 100644 (file)
@@ -69,14 +69,14 @@ static inline void cancel_mac_stats_update(struct adapter *ap)
        cancel_delayed_work(&ap->stats_update_task);
 }
 
-#define MAX_CMDQ_ENTRIES 16384
-#define MAX_CMDQ1_ENTRIES 1024
-#define MAX_RX_BUFFERS 16384
-#define MAX_RX_JUMBO_BUFFERS 16384
+#define MAX_CMDQ_ENTRIES       16384
+#define MAX_CMDQ1_ENTRIES      1024
+#define MAX_RX_BUFFERS         16384
+#define MAX_RX_JUMBO_BUFFERS   16384
 #define MAX_TX_BUFFERS_HIGH    16384U
 #define MAX_TX_BUFFERS_LOW     1536U
 #define MAX_TX_BUFFERS         1460U
-#define MIN_FL_ENTRIES 32
+#define MIN_FL_ENTRIES         32
 
 #define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
                         NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
@@ -143,7 +143,7 @@ static void link_report(struct port_info *p)
                        case SPEED_100:   s = "100Mbps"; break;
                }
 
-       printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
+               printk(KERN_INFO "%s: link up, %s, %s-duplex\n",
                       p->dev->name, s,
                       p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
        }
@@ -233,7 +233,7 @@ static int cxgb_up(struct adapter *adapter)
 
        t1_sge_start(adapter->sge);
        t1_interrupts_enable(adapter);
- out_err:
+out_err:
        return err;
 }
 
@@ -454,51 +454,21 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
        const struct cmac_statistics *s;
        const struct sge_intr_counts *t;
        struct sge_port_stats ss;
+       unsigned int len;
 
        s = mac->ops->statistics_update(mac, MAC_STATS_UPDATE_FULL);
 
-       *data++ = s->TxOctetsOK;
-       *data++ = s->TxOctetsBad;
-       *data++ = s->TxUnicastFramesOK;
-       *data++ = s->TxMulticastFramesOK;
-       *data++ = s->TxBroadcastFramesOK;
-       *data++ = s->TxPauseFrames;
-       *data++ = s->TxFramesWithDeferredXmissions;
-       *data++ = s->TxLateCollisions;
-       *data++ = s->TxTotalCollisions;
-       *data++ = s->TxFramesAbortedDueToXSCollisions;
-       *data++ = s->TxUnderrun;
-       *data++ = s->TxLengthErrors;
-       *data++ = s->TxInternalMACXmitError;
-       *data++ = s->TxFramesWithExcessiveDeferral;
-       *data++ = s->TxFCSErrors;
-
-       *data++ = s->RxOctetsOK;
-       *data++ = s->RxOctetsBad;
-       *data++ = s->RxUnicastFramesOK;
-       *data++ = s->RxMulticastFramesOK;
-       *data++ = s->RxBroadcastFramesOK;
-       *data++ = s->RxPauseFrames;
-       *data++ = s->RxFCSErrors;
-       *data++ = s->RxAlignErrors;
-       *data++ = s->RxSymbolErrors;
-       *data++ = s->RxDataErrors;
-       *data++ = s->RxSequenceErrors;
-       *data++ = s->RxRuntErrors;
-       *data++ = s->RxJabberErrors;
-       *data++ = s->RxInternalMACRcvError;
-       *data++ = s->RxInRangeLengthErrors;
-       *data++ = s->RxOutOfRangeLengthField;
-       *data++ = s->RxFrameTooLongErrors;
+       len = sizeof(u64)*(&s->TxFCSErrors + 1 - &s->TxOctetsOK);
+       memcpy(data, &s->TxOctetsOK, len);
+       data += len;
+
+       len = sizeof(u64)*(&s->RxFrameTooLongErrors + 1 - &s->RxOctetsOK);
+       memcpy(data, &s->RxOctetsOK, len);
+       data += len;
 
        t1_sge_get_port_stats(adapter->sge, dev->if_port, &ss);
-       *data++ = ss.rx_packets;
-       *data++ = ss.rx_cso_good;
-       *data++ = ss.tx_packets;
-       *data++ = ss.tx_cso;
-       *data++ = ss.tx_tso;
-       *data++ = ss.vlan_xtract;
-       *data++ = ss.vlan_insert;
+       memcpy(data, &ss, sizeof(ss));
+       data += sizeof(ss);
 
        t = t1_sge_get_intr_counts(adapter->sge);
        *data++ = t->rx_drops;
@@ -749,7 +719,7 @@ static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
                return -EINVAL;
 
        if (adapter->flags & FULL_INIT_DONE)
-       return -EBUSY;
+               return -EBUSY;
 
        adapter->params.sge.freelQ_size[!jumbo_fl] = e->rx_pending;
        adapter->params.sge.freelQ_size[jumbo_fl] = e->rx_jumbo_pending;
@@ -764,7 +734,7 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
        struct adapter *adapter = dev->priv;
 
        adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs;
-       adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce;
+       adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce;
        adapter->params.sge.sample_interval_usecs = c->rate_sample_interval;
        t1_sge_set_coalesce_params(adapter->sge, &adapter->params.sge);
        return 0;
@@ -782,9 +752,9 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
 
 static int get_eeprom_len(struct net_device *dev)
 {
-       struct adapter *adapter = dev->priv;
+       struct adapter *adapter = dev->priv;
 
-       return t1_is_asic(adapter) ? EEPROM_SIZE : 0;
+       return t1_is_asic(adapter) ? EEPROM_SIZE : 0;
 }
 
 #define EEPROM_MAGIC(ap) \
@@ -848,7 +818,7 @@ static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
                u32 val;
 
                if (!phy->mdio_read)
-           return -EOPNOTSUPP;
+                       return -EOPNOTSUPP;
                phy->mdio_read(adapter, data->phy_id, 0, data->reg_num & 0x1f,
                               &val);
                data->val_out = val;
@@ -860,7 +830,7 @@ static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
                if (!capable(CAP_NET_ADMIN))
                    return -EPERM;
                if (!phy->mdio_write)
-           return -EOPNOTSUPP;
+                       return -EOPNOTSUPP;
                phy->mdio_write(adapter, data->phy_id, 0, data->reg_num & 0x1f,
                                data->val_in);
                break;
@@ -879,9 +849,9 @@ static int t1_change_mtu(struct net_device *dev, int new_mtu)
        struct cmac *mac = adapter->port[dev->if_port].mac;
 
        if (!mac->ops->set_mtu)
-       return -EOPNOTSUPP;
+               return -EOPNOTSUPP;
        if (new_mtu < 68)
-       return -EINVAL;
+               return -EINVAL;
        if ((ret = mac->ops->set_mtu(mac, new_mtu)))
                return ret;
        dev->mtu = new_mtu;
@@ -1211,9 +1181,9 @@ static int __devinit init_one(struct pci_dev *pdev,
 
        return 0;
 
- out_release_adapter_res:
+out_release_adapter_res:
        t1_free_sw_modules(adapter);
- out_free_dev:
+out_free_dev:
        if (adapter) {
                if (adapter->regs)
                        iounmap(adapter->regs);
@@ -1222,7 +1192,7 @@ static int __devinit init_one(struct pci_dev *pdev,
                                free_netdev(adapter->port[i].dev);
        }
        pci_release_regions(pdev);
- out_disable_pdev:
+out_disable_pdev:
        pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
        return err;
@@ -1273,28 +1243,27 @@ static int t1_clock(struct adapter *adapter, int mode)
        int M_MEM_VAL;
 
        enum {
-               M_CORE_BITS = 9,
-               T_CORE_VAL = 0,
-               T_CORE_BITS = 2,
-               N_CORE_VAL = 0,
-               N_CORE_BITS = 2,
-               M_MEM_BITS = 9,
-               T_MEM_VAL = 0,
-               T_MEM_BITS = 2,
-               N_MEM_VAL = 0,
-               N_MEM_BITS = 2,
-               NP_LOAD = 1 << 17,
-               S_LOAD_MEM = 1 << 5,
-               S_LOAD_CORE = 1 << 6,
-               S_CLOCK = 1 << 3
+               M_CORE_BITS     = 9,
+               T_CORE_VAL      = 0,
+               T_CORE_BITS     = 2,
+               N_CORE_VAL      = 0,
+               N_CORE_BITS     = 2,
+               M_MEM_BITS      = 9,
+               T_MEM_VAL       = 0,
+               T_MEM_BITS      = 2,
+               N_MEM_VAL       = 0,
+               N_MEM_BITS      = 2,
+               NP_LOAD         = 1 << 17,
+               S_LOAD_MEM      = 1 << 5,
+               S_LOAD_CORE     = 1 << 6,
+               S_CLOCK         = 1 << 3
        };
 
        if (!t1_is_T1B(adapter))
                return -ENODEV; /* Can't re-clock this chip. */
 
-       if (mode & 2) {
+       if (mode & 2)
                return 0;       /* show current mode. */
-       }
 
        if ((adapter->t1powersave & 1) == (mode & 1))
                return -EALREADY;       /* ASIC already running in mode. */
@@ -1386,26 +1355,26 @@ static inline void t1_sw_reset(struct pci_dev *pdev)
 static void __devexit remove_one(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
+       struct adapter *adapter = dev->priv;
+       int i;
 
-       if (dev) {
-               int i;
-               struct adapter *adapter = dev->priv;
-
-               for_each_port(adapter, i)
-                       if (test_bit(i, &adapter->registered_device_map))
-                               unregister_netdev(adapter->port[i].dev);
+       for_each_port(adapter, i) {
+               if (test_bit(i, &adapter->registered_device_map))
+                       unregister_netdev(adapter->port[i].dev);
+       }
 
-               t1_free_sw_modules(adapter);
-               iounmap(adapter->regs);
-               while (--i >= 0)
-                       if (adapter->port[i].dev)
-                               free_netdev(adapter->port[i].dev);
+       t1_free_sw_modules(adapter);
+       iounmap(adapter->regs);
 
-               pci_release_regions(pdev);
-               pci_disable_device(pdev);
-               pci_set_drvdata(pdev, NULL);
-               t1_sw_reset(pdev);
+       while (--i >= 0) {
+               if (adapter->port[i].dev)
+                       free_netdev(adapter->port[i].dev);
        }
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       t1_sw_reset(pdev);
 }
 
 static struct pci_driver driver = {
index 9ebecaa..eef655c 100644 (file)
@@ -46,14 +46,14 @@ enum {
 };
 
 /* ELMER0 registers */
-#define A_ELMER0_VERSION 0x100000
-#define A_ELMER0_PHY_CFG 0x100004
-#define A_ELMER0_INT_ENABLE 0x100008
-#define A_ELMER0_INT_CAUSE 0x10000c
-#define A_ELMER0_GPI_CFG 0x100010
-#define A_ELMER0_GPI_STAT 0x100014
-#define A_ELMER0_GPO 0x100018
-#define A_ELMER0_PORT0_MI1_CFG 0x400000
+#define A_ELMER0_VERSION       0x100000
+#define A_ELMER0_PHY_CFG       0x100004
+#define A_ELMER0_INT_ENABLE    0x100008
+#define A_ELMER0_INT_CAUSE     0x10000c
+#define A_ELMER0_GPI_CFG       0x100010
+#define A_ELMER0_GPI_STAT      0x100014
+#define A_ELMER0_GPO           0x100018
+#define A_ELMER0_PORT0_MI1_CFG 0x400000
 
 #define S_MI1_MDI_ENABLE    0
 #define V_MI1_MDI_ENABLE(x) ((x) << S_MI1_MDI_ENABLE)
@@ -111,18 +111,18 @@ enum {
 #define V_MI1_OP_BUSY(x) ((x) << S_MI1_OP_BUSY)
 #define F_MI1_OP_BUSY    V_MI1_OP_BUSY(1U)
 
-#define A_ELMER0_PORT1_MI1_CFG 0x500000
-#define A_ELMER0_PORT1_MI1_ADDR 0x500004
-#define A_ELMER0_PORT1_MI1_DATA 0x500008
-#define A_ELMER0_PORT1_MI1_OP 0x50000c
-#define A_ELMER0_PORT2_MI1_CFG 0x600000
-#define A_ELMER0_PORT2_MI1_ADDR 0x600004
-#define A_ELMER0_PORT2_MI1_DATA 0x600008
-#define A_ELMER0_PORT2_MI1_OP 0x60000c
-#define A_ELMER0_PORT3_MI1_CFG 0x700000
-#define A_ELMER0_PORT3_MI1_ADDR 0x700004
-#define A_ELMER0_PORT3_MI1_DATA 0x700008
-#define A_ELMER0_PORT3_MI1_OP 0x70000c
+#define A_ELMER0_PORT1_MI1_CFG 0x500000
+#define A_ELMER0_PORT1_MI1_ADDR        0x500004
+#define A_ELMER0_PORT1_MI1_DATA        0x500008
+#define A_ELMER0_PORT1_MI1_OP  0x50000c
+#define A_ELMER0_PORT2_MI1_CFG 0x600000
+#define A_ELMER0_PORT2_MI1_ADDR        0x600004
+#define A_ELMER0_PORT2_MI1_DATA        0x600008
+#define A_ELMER0_PORT2_MI1_OP  0x60000c
+#define A_ELMER0_PORT3_MI1_CFG 0x700000
+#define A_ELMER0_PORT3_MI1_ADDR        0x700004
+#define A_ELMER0_PORT3_MI1_DATA        0x700008
+#define A_ELMER0_PORT3_MI1_OP  0x70000c
 
 /* Simple bit definition for GPI and GP0 registers. */
 #define     ELMER0_GP_BIT0              0x0001
index 4192f0f..d7c5406 100644 (file)
@@ -202,9 +202,9 @@ static void espi_setup_for_pm3393(adapter_t *adapter)
 
 static void espi_setup_for_vsc7321(adapter_t *adapter)
 {
-        writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
-        writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1);
-        writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
+       writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN0);
+       writel(0x1f401f4, adapter->regs + A_ESPI_SCH_TOKEN1);
+       writel(0x1f4, adapter->regs + A_ESPI_SCH_TOKEN2);
        writel(0xa00, adapter->regs + A_ESPI_RX_FIFO_ALMOST_FULL_WATERMARK);
        writel(0x1ff, adapter->regs + A_ESPI_RX_FIFO_ALMOST_EMPTY_WATERMARK);
        writel(1, adapter->regs + A_ESPI_CALENDAR_LENGTH);
@@ -247,10 +247,10 @@ int t1_espi_init(struct peespi *espi, int mac_type, int nports)
                writel(V_OUT_OF_SYNC_COUNT(4) |
                       V_DIP2_PARITY_ERR_THRES(3) |
                       V_DIP4_THRES(1), adapter->regs + A_ESPI_MISC_CONTROL);
-               writel(nports == 4 ? 0x200040 : 0x1000080,
+               writel(nports == 4 ? 0x200040 : 0x1000080,
                       adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
        } else
-               writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
+               writel(0x800100, adapter->regs + A_ESPI_MAXBURST1_MAXBURST2);
 
        if (mac_type == CHBT_MAC_PM3393)
                espi_setup_for_pm3393(adapter);
@@ -301,7 +301,8 @@ void t1_espi_set_misc_ctrl(adapter_t *adapter, u32 val)
 {
        struct peespi *espi = adapter->espi;
 
-       if (!is_T2(adapter)) return;
+       if (!is_T2(adapter))
+               return;
        spin_lock(&espi->lock);
        espi->misc_ctrl = (val & ~MON_MASK) |
                          (espi->misc_ctrl & MON_MASK);
@@ -340,32 +341,31 @@ u32 t1_espi_get_mon(adapter_t *adapter, u32 addr, u8 wait)
  * compare with t1_espi_get_mon(), it reads espiInTxSop[0 ~ 3] in
  * one shot, since there is no per port counter on the out side.
  */
-int
-t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait)
+int t1_espi_get_mon_t204(adapter_t *adapter, u32 *valp, u8 wait)
 {
-        struct peespi *espi = adapter->espi;
+       struct peespi *espi = adapter->espi;
        u8 i, nport = (u8)adapter->params.nports;
 
-        if (!wait) {
-                if (!spin_trylock(&espi->lock))
-                        return -1;
-        } else
-                spin_lock(&espi->lock);
+       if (!wait) {
+               if (!spin_trylock(&espi->lock))
+                       return -1;
+       } else
+               spin_lock(&espi->lock);
 
-       if ( (espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION ) {
+       if ((espi->misc_ctrl & MON_MASK) != F_MONITORED_DIRECTION) {
                espi->misc_ctrl = (espi->misc_ctrl & ~MON_MASK) |
                                        F_MONITORED_DIRECTION;
-                writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
-       }
+               writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+       }
        for (i = 0 ; i < nport; i++, valp++) {
                if (i) {
                        writel(espi->misc_ctrl | V_MONITORED_PORT_NUM(i),
                               adapter->regs + A_ESPI_MISC_CONTROL);
                }
-                *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
-        }
+               *valp = readl(adapter->regs + A_ESPI_SCH_TOKEN3);
+       }
 
-        writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
-        spin_unlock(&espi->lock);
-        return 0;
+       writel(espi->misc_ctrl, adapter->regs + A_ESPI_MISC_CONTROL);
+       spin_unlock(&espi->lock);
+       return 0;
 }
index 17a3c2b..ccdb2bc 100644 (file)
@@ -98,9 +98,9 @@
 #define A_MI0_DATA_INT 0xb10
 
 /* GMAC registers */
-#define A_GMAC_MACID_LO 0x28
-#define A_GMAC_MACID_HI 0x2c
-#define A_GMAC_CSR 0x30
+#define A_GMAC_MACID_LO        0x28
+#define A_GMAC_MACID_HI        0x2c
+#define A_GMAC_CSR     0x30
 
 #define S_INTERFACE    0
 #define M_INTERFACE    0x3
index a2b8ad9..006a2eb 100644 (file)
 
 #include "common.h"
 
-enum { MAC_STATS_UPDATE_FAST, MAC_STATS_UPDATE_FULL };
-enum { MAC_DIRECTION_RX = 1, MAC_DIRECTION_TX = 2 };
+enum {
+       MAC_STATS_UPDATE_FAST,
+       MAC_STATS_UPDATE_FULL
+};
+
+enum {
+       MAC_DIRECTION_RX = 1,
+       MAC_DIRECTION_TX = 2
+};
 
 struct cmac_statistics {
        /* Transmit */
index 5b8f144..10b2a9a 100644 (file)
@@ -145,48 +145,61 @@ static void disable_port(struct cmac *mac)
        t1_tpi_write(mac->adapter, REG_PORT_ENABLE, val);
 }
 
-#define RMON_UPDATE(mac, name, stat_name) \
-       t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
-       (mac)->stats.stat_name += val;
-
 /*
  * Read the current values of the RMON counters and add them to the cumulative
  * port statistics.  The HW RMON counters are cleared by this operation.
  */
 static void port_stats_update(struct cmac *mac)
 {
-       u32 val;
+       static struct {
+               unsigned int reg;
+               unsigned int offset;
+       } hw_stats[] = {
+
+#define HW_STAT(name, stat_name) \
+       { REG_##name, \
+         (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+               /* Rx stats */
+               HW_STAT(RxOctetsTotalOK, RxOctetsOK),
+               HW_STAT(RxOctetsBad, RxOctetsBad),
+               HW_STAT(RxUCPkts, RxUnicastFramesOK),
+               HW_STAT(RxMCPkts, RxMulticastFramesOK),
+               HW_STAT(RxBCPkts, RxBroadcastFramesOK),
+               HW_STAT(RxJumboPkts, RxJumboFramesOK),
+               HW_STAT(RxFCSErrors, RxFCSErrors),
+               HW_STAT(RxAlignErrors, RxAlignErrors),
+               HW_STAT(RxLongErrors, RxFrameTooLongErrors),
+               HW_STAT(RxVeryLongErrors, RxFrameTooLongErrors),
+               HW_STAT(RxPauseMacControlCounter, RxPauseFrames),
+               HW_STAT(RxDataErrors, RxDataErrors),
+               HW_STAT(RxJabberErrors, RxJabberErrors),
+               HW_STAT(RxRuntErrors, RxRuntErrors),
+               HW_STAT(RxShortErrors, RxRuntErrors),
+               HW_STAT(RxSequenceErrors, RxSequenceErrors),
+               HW_STAT(RxSymbolErrors, RxSymbolErrors),
+
+               /* Tx stats (skip collision stats as we are full-duplex only) */
+               HW_STAT(TxOctetsTotalOK, TxOctetsOK),
+               HW_STAT(TxOctetsBad, TxOctetsBad),
+               HW_STAT(TxUCPkts, TxUnicastFramesOK),
+               HW_STAT(TxMCPkts, TxMulticastFramesOK),
+               HW_STAT(TxBCPkts, TxBroadcastFramesOK),
+               HW_STAT(TxJumboPkts, TxJumboFramesOK),
+               HW_STAT(TxPauseFrames, TxPauseFrames),
+               HW_STAT(TxExcessiveLengthDrop, TxLengthErrors),
+               HW_STAT(TxUnderrun, TxUnderrun),
+               HW_STAT(TxCRCErrors, TxFCSErrors)
+       }, *p = hw_stats;
+       u64 *stats = (u64 *) &mac->stats;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
+               u32 val;
 
-       /* Rx stats */
-       RMON_UPDATE(mac, RxOctetsTotalOK, RxOctetsOK);
-       RMON_UPDATE(mac, RxOctetsBad, RxOctetsBad);
-       RMON_UPDATE(mac, RxUCPkts, RxUnicastFramesOK);
-       RMON_UPDATE(mac, RxMCPkts, RxMulticastFramesOK);
-       RMON_UPDATE(mac, RxBCPkts, RxBroadcastFramesOK);
-       RMON_UPDATE(mac, RxJumboPkts, RxJumboFramesOK);
-       RMON_UPDATE(mac, RxFCSErrors, RxFCSErrors);
-       RMON_UPDATE(mac, RxAlignErrors, RxAlignErrors);
-       RMON_UPDATE(mac, RxLongErrors, RxFrameTooLongErrors);
-       RMON_UPDATE(mac, RxVeryLongErrors, RxFrameTooLongErrors);
-       RMON_UPDATE(mac, RxPauseMacControlCounter, RxPauseFrames);
-       RMON_UPDATE(mac, RxDataErrors, RxDataErrors);
-       RMON_UPDATE(mac, RxJabberErrors, RxJabberErrors);
-       RMON_UPDATE(mac, RxRuntErrors, RxRuntErrors);
-       RMON_UPDATE(mac, RxShortErrors, RxRuntErrors);
-       RMON_UPDATE(mac, RxSequenceErrors, RxSequenceErrors);
-       RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
-
-       /* Tx stats (skip collision stats as we are full-duplex only) */
-       RMON_UPDATE(mac, TxOctetsTotalOK, TxOctetsOK);
-       RMON_UPDATE(mac, TxOctetsBad, TxOctetsBad);
-       RMON_UPDATE(mac, TxUCPkts, TxUnicastFramesOK);
-       RMON_UPDATE(mac, TxMCPkts, TxMulticastFramesOK);
-       RMON_UPDATE(mac, TxBCPkts, TxBroadcastFramesOK);
-       RMON_UPDATE(mac, TxJumboPkts, TxJumboFramesOK);
-       RMON_UPDATE(mac, TxPauseFrames, TxPauseFrames);
-       RMON_UPDATE(mac, TxExcessiveLengthDrop, TxLengthErrors);
-       RMON_UPDATE(mac, TxUnderrun, TxUnderrun);
-       RMON_UPDATE(mac, TxCRCErrors, TxFCSErrors);
+               t1_tpi_read(mac->adapter, MACREG(mac, p->reg), &val);
+               stats[p->offset] += val;
+       }
 }
 
 /* No-op interrupt operation as this MAC does not support interrupts */
@@ -273,7 +286,8 @@ static int mac_set_rx_mode(struct cmac *mac, struct t1_rx_mode *rm)
 static int mac_set_mtu(struct cmac *mac, int mtu)
 {
        /* MAX_FRAME_SIZE inludes header + FCS, mtu doesn't */
-       if (mtu > (MAX_FRAME_SIZE - 14 - 4)) return -EINVAL;
+       if (mtu > (MAX_FRAME_SIZE - 14 - 4))
+               return -EINVAL;
        t1_tpi_write(mac->adapter, MACREG(mac, REG_MAX_FRAME_SIZE),
                     mtu + 14 + 4);
        return 0;
@@ -357,8 +371,8 @@ static void enable_port(struct cmac *mac)
        val |= (1 << index);
        t1_tpi_write(adapter, REG_PORT_ENABLE, val);
 
-               index <<= 2;
-        if (is_T2(adapter)) {
+       index <<= 2;
+       if (is_T2(adapter)) {
                /* T204: set the Fifo water level & threshold */
                t1_tpi_write(adapter, RX_FIFO_HIGH_WATERMARK_BASE + index, 0x740);
                t1_tpi_write(adapter, RX_FIFO_LOW_WATERMARK_BASE + index, 0x730);
@@ -389,6 +403,10 @@ static int mac_disable(struct cmac *mac, int which)
        return 0;
 }
 
+#define RMON_UPDATE(mac, name, stat_name) \
+       t1_tpi_read((mac)->adapter, MACREG(mac, REG_##name), &val); \
+       (mac)->stats.stat_name += val;
+
 /*
  * This function is called periodically to accumulate the current values of the
  * RMON counters into the port statistics.  Since the counters are only 32 bits
@@ -460,10 +478,12 @@ static struct cmac *ixf1010_mac_create(adapter_t *adapter, int index)
        struct cmac *mac;
        u32 val;
 
-       if (index > 9) return NULL;
+       if (index > 9)
+               return NULL;
 
        mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
-       if (!mac) return NULL;
+       if (!mac)
+               return NULL;
 
        mac->ops = &ixf1010_ops;
        mac->instance = (cmac_instance *)(mac + 1);
index 28ac93f..5867e3b 100644 (file)
@@ -73,9 +73,8 @@ static int mv88e1xxx_interrupt_enable(struct cphy *cphy)
 
                t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
                elmer |= ELMER0_GP_BIT1;
-               if (is_T2(cphy->adapter)) {
-                   elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
-                }
+               if (is_T2(cphy->adapter))
+                   elmer |= ELMER0_GP_BIT2 | ELMER0_GP_BIT3 | ELMER0_GP_BIT4;
                t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
        }
        return 0;
@@ -92,9 +91,8 @@ static int mv88e1xxx_interrupt_disable(struct cphy *cphy)
 
                t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
                elmer &= ~ELMER0_GP_BIT1;
-               if (is_T2(cphy->adapter)) {
+               if (is_T2(cphy->adapter))
                    elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
-                }
                t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
        }
        return 0;
@@ -112,9 +110,8 @@ static int mv88e1xxx_interrupt_clear(struct cphy *cphy)
        if (t1_is_asic(cphy->adapter)) {
                t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
                elmer |= ELMER0_GP_BIT1;
-               if (is_T2(cphy->adapter)) {
+               if (is_T2(cphy->adapter))
                    elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
-                }
                t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
        }
        return 0;
@@ -300,7 +297,7 @@ static int mv88e1xxx_interrupt_handler(struct cphy *cphy)
 
        /*
         * Loop until cause reads zero. Need to handle bouncing interrupts.
-         */
+        */
        while (1) {
                u32 cause;
 
@@ -308,15 +305,16 @@ static int mv88e1xxx_interrupt_handler(struct cphy *cphy)
                                MV88E1XXX_INTERRUPT_STATUS_REGISTER,
                                &cause);
                cause &= INTR_ENABLE_MASK;
-               if (!cause) break;
+               if (!cause)
+                       break;
 
                if (cause & MV88E1XXX_INTR_LINK_CHNG) {
                        (void) simple_mdio_read(cphy,
                                MV88E1XXX_SPECIFIC_STATUS_REGISTER, &status);
 
-                       if (status & MV88E1XXX_INTR_LINK_CHNG) {
+                       if (status & MV88E1XXX_INTR_LINK_CHNG)
                                cphy->state |= PHY_LINK_UP;
-                       else {
+                       else {
                                cphy->state &= ~PHY_LINK_UP;
                                if (cphy->state & PHY_AUTONEG_EN)
                                        cphy->state &= ~PHY_AUTONEG_RDY;
@@ -360,7 +358,8 @@ static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
 {
        struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
 
-       if (!cphy) return NULL;
+       if (!cphy)
+               return NULL;
 
        cphy_init(cphy, adapter, phy_addr, &mv88e1xxx_ops, mdio_ops);
 
@@ -377,11 +376,11 @@ static struct cphy *mv88e1xxx_phy_create(adapter_t *adapter, int phy_addr,
        }
        (void) mv88e1xxx_downshift_set(cphy, 1);   /* Enable downshift */
 
-        /* LED */
+       /* LED */
        if (is_T2(adapter)) {
                (void) simple_mdio_write(cphy,
                                MV88E1XXX_LED_CONTROL_REGISTER, 0x1);
-        }
+       }
 
        return cphy;
 }
index 82fed1d..87dde3e 100644 (file)
@@ -10,25 +10,25 @@ static int my3126_reset(struct cphy *cphy, int wait)
         * This can be done through registers.  It is not required since
         * a full chip reset is used.
         */
-       return (0);
+       return 0;
 }
 
 static int my3126_interrupt_enable(struct cphy *cphy)
 {
        schedule_delayed_work(&cphy->phy_update, HZ/30);
        t1_tpi_read(cphy->adapter, A_ELMER0_GPO, &cphy->elmer_gpo);
-       return (0);
+       return 0;
 }
 
 static int my3126_interrupt_disable(struct cphy *cphy)
 {
        cancel_rearming_delayed_work(&cphy->phy_update);
-       return (0);
+       return 0;
 }
 
 static int my3126_interrupt_clear(struct cphy *cphy)
 {
-       return (0);
+       return 0;
 }
 
 #define OFFSET(REG_ADDR)    (REG_ADDR << 2)
@@ -102,7 +102,7 @@ static void my3216_poll(struct work_struct *work)
 
 static int my3126_set_loopback(struct cphy *cphy, int on)
 {
-       return (0);
+       return 0;
 }
 
 /* To check the activity LED */
@@ -146,7 +146,7 @@ static int my3126_get_link_status(struct cphy *cphy,
        if (fc)
                *fc = PAUSE_RX | PAUSE_TX;
 
-       return (0);
+       return 0;
 }
 
 static void my3126_destroy(struct cphy *cphy)
@@ -177,7 +177,7 @@ static struct cphy *my3126_phy_create(adapter_t *adapter,
        INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll);
        cphy->bmsr = 0;
 
-       return (cphy);
+       return cphy;
 }
 
 /* Chip Reset */
@@ -198,7 +198,7 @@ static int my3126_phy_reset(adapter_t * adapter)
        val |= 0x8000;
        t1_tpi_write(adapter, A_ELMER0_GPO, val);
        udelay(100);
-       return (0);
+       return 0;
 }
 
 struct gphy t1_my3126_ops = {
index 63cabeb..69129ed 100644 (file)
@@ -446,17 +446,51 @@ static void pm3393_rmon_update(struct adapter *adapter, u32 offs, u64 *val,
                *val += 1ull << 40;
 }
 
-#define RMON_UPDATE(mac, name, stat_name) \
-       pm3393_rmon_update((mac)->adapter, OFFSET(name),                \
-                          &(mac)->stats.stat_name,                     \
-                  (ro &((name - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW) >> 2)))
-
-
 static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
                                                              int flag)
 {
-       u64     ro;
-       u32     val0, val1, val2, val3;
+       static struct {
+               unsigned int reg;
+               unsigned int offset;
+       } hw_stats [] = {
+
+#define HW_STAT(name, stat_name) \
+       { name, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+               /* Rx stats */
+               HW_STAT(RxOctetsReceivedOK, RxOctetsOK),
+               HW_STAT(RxUnicastFramesReceivedOK, RxUnicastFramesOK),
+               HW_STAT(RxMulticastFramesReceivedOK, RxMulticastFramesOK),
+               HW_STAT(RxBroadcastFramesReceivedOK, RxBroadcastFramesOK),
+               HW_STAT(RxPAUSEMACCtrlFramesReceived, RxPauseFrames),
+               HW_STAT(RxFrameCheckSequenceErrors, RxFCSErrors),
+               HW_STAT(RxFramesLostDueToInternalMACErrors,
+                               RxInternalMACRcvError),
+               HW_STAT(RxSymbolErrors, RxSymbolErrors),
+               HW_STAT(RxInRangeLengthErrors, RxInRangeLengthErrors),
+               HW_STAT(RxFramesTooLongErrors , RxFrameTooLongErrors),
+               HW_STAT(RxJabbers, RxJabberErrors),
+               HW_STAT(RxFragments, RxRuntErrors),
+               HW_STAT(RxUndersizedFrames, RxRuntErrors),
+               HW_STAT(RxJumboFramesReceivedOK, RxJumboFramesOK),
+               HW_STAT(RxJumboOctetsReceivedOK, RxJumboOctetsOK),
+
+               /* Tx stats */
+               HW_STAT(TxOctetsTransmittedOK, TxOctetsOK),
+               HW_STAT(TxFramesLostDueToInternalMACTransmissionError,
+                               TxInternalMACXmitError),
+               HW_STAT(TxTransmitSystemError, TxFCSErrors),
+               HW_STAT(TxUnicastFramesTransmittedOK, TxUnicastFramesOK),
+               HW_STAT(TxMulticastFramesTransmittedOK, TxMulticastFramesOK),
+               HW_STAT(TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK),
+               HW_STAT(TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames),
+               HW_STAT(TxJumboFramesReceivedOK, TxJumboFramesOK),
+               HW_STAT(TxJumboOctetsReceivedOK, TxJumboOctetsOK)
+       }, *p = hw_stats;
+       u64 ro;
+       u32 val0, val1, val2, val3;
+       u64 *stats = (u64 *) &mac->stats;
+       unsigned int i;
 
        /* Snap the counters */
        pmwrite(mac, SUNI1x10GEXP_REG_MSTAT_CONTROL,
@@ -470,35 +504,14 @@ static const struct cmac_statistics *pm3393_update_statistics(struct cmac *mac,
        ro = ((u64)val0 & 0xffff) | (((u64)val1 & 0xffff) << 16) |
                (((u64)val2 & 0xffff) << 32) | (((u64)val3 & 0xffff) << 48);
 
-       /* Rx stats */
-       RMON_UPDATE(mac, RxOctetsReceivedOK, RxOctetsOK);
-       RMON_UPDATE(mac, RxUnicastFramesReceivedOK, RxUnicastFramesOK);
-       RMON_UPDATE(mac, RxMulticastFramesReceivedOK, RxMulticastFramesOK);
-       RMON_UPDATE(mac, RxBroadcastFramesReceivedOK, RxBroadcastFramesOK);
-       RMON_UPDATE(mac, RxPAUSEMACCtrlFramesReceived, RxPauseFrames);
-       RMON_UPDATE(mac, RxFrameCheckSequenceErrors, RxFCSErrors);
-       RMON_UPDATE(mac, RxFramesLostDueToInternalMACErrors,
-                               RxInternalMACRcvError);
-       RMON_UPDATE(mac, RxSymbolErrors, RxSymbolErrors);
-       RMON_UPDATE(mac, RxInRangeLengthErrors, RxInRangeLengthErrors);
-       RMON_UPDATE(mac, RxFramesTooLongErrors , RxFrameTooLongErrors);
-       RMON_UPDATE(mac, RxJabbers, RxJabberErrors);
-       RMON_UPDATE(mac, RxFragments, RxRuntErrors);
-       RMON_UPDATE(mac, RxUndersizedFrames, RxRuntErrors);
-       RMON_UPDATE(mac, RxJumboFramesReceivedOK, RxJumboFramesOK);
-       RMON_UPDATE(mac, RxJumboOctetsReceivedOK, RxJumboOctetsOK);
-
-       /* Tx stats */
-       RMON_UPDATE(mac, TxOctetsTransmittedOK, TxOctetsOK);
-       RMON_UPDATE(mac, TxFramesLostDueToInternalMACTransmissionError,
-                               TxInternalMACXmitError);
-       RMON_UPDATE(mac, TxTransmitSystemError, TxFCSErrors);
-       RMON_UPDATE(mac, TxUnicastFramesTransmittedOK, TxUnicastFramesOK);
-       RMON_UPDATE(mac, TxMulticastFramesTransmittedOK, TxMulticastFramesOK);
-       RMON_UPDATE(mac, TxBroadcastFramesTransmittedOK, TxBroadcastFramesOK);
-       RMON_UPDATE(mac, TxPAUSEMACCtrlFramesTransmitted, TxPauseFrames);
-       RMON_UPDATE(mac, TxJumboFramesReceivedOK, TxJumboFramesOK);
-       RMON_UPDATE(mac, TxJumboOctetsReceivedOK, TxJumboOctetsOK);
+       for (i = 0; i < ARRAY_SIZE(hw_stats); i++) {
+               unsigned reg = p->reg - SUNI1x10GEXP_REG_MSTAT_COUNTER_0_LOW;
+
+               pm3393_rmon_update((mac)->adapter, OFFSET(p->reg),
+                                  stats + p->offset, ro & (reg >> 2));
+       }
+
+
 
        return &mac->stats;
 }
@@ -534,9 +547,9 @@ static int pm3393_macaddress_set(struct cmac *cmac, u8 ma[6])
        /* Store local copy */
        memcpy(cmac->instance->mac_addr, ma, 6);
 
-       lo = ((u32) ma[1] << 8) | (u32) ma[0];
+       lo  = ((u32) ma[1] << 8) | (u32) ma[0];
        mid = ((u32) ma[3] << 8) | (u32) ma[2];
-       hi = ((u32) ma[5] << 8) | (u32) ma[4];
+       hi  = ((u32) ma[5] << 8) | (u32) ma[4];
 
        /* Disable Rx/Tx MAC before configuring it. */
        if (enabled)
index 659cb22..89a6827 100644 (file)
 #define SGE_FREEL_REFILL_THRESH        16
 #define SGE_RESPQ_E_N          1024
 #define SGE_INTRTIMER_NRES     1000
-#define SGE_RX_COPY_THRES      256
 #define SGE_RX_SM_BUF_SIZE     1536
 #define SGE_TX_DESC_MAX_PLEN   16384
 
-# define SGE_RX_DROP_THRES 2
-
 #define SGE_RESPQ_REPLENISH_THRES (SGE_RESPQ_E_N / 4)
 
 /*
  */
 #define TX_RECLAIM_PERIOD (HZ / 4)
 
-#ifndef NET_IP_ALIGN
-# define NET_IP_ALIGN 2
-#endif
-
 #define M_CMD_LEN       0x7fffffff
 #define V_CMD_LEN(v)    (v)
 #define G_CMD_LEN(v)    ((v) & M_CMD_LEN)
@@ -195,7 +188,7 @@ struct cmdQ {
        struct cmdQ_e  *entries;        /* HW command descriptor Q */
        struct cmdQ_ce *centries;       /* SW command context descriptor Q */
        dma_addr_t      dma_addr;       /* DMA addr HW command descriptor Q */
-       spinlock_t      lock;           /* Lock to protect cmdQ enqueuing */
+       spinlock_t      lock;           /* Lock to protect cmdQ enqueuing */
 };
 
 struct freelQ {
@@ -241,9 +234,9 @@ struct sched_port {
 /* Per T204 device */
 struct sched {
        ktime_t         last_updated;   /* last time quotas were computed */
-       unsigned int    max_avail;      /* max bits to be sent to any port */
-       unsigned int    port;           /* port index (round robin ports) */
-       unsigned int    num;            /* num skbs in per port queues */
+       unsigned int    max_avail;      /* max bits to be sent to any port */
+       unsigned int    port;           /* port index (round robin ports) */
+       unsigned int    num;            /* num skbs in per port queues */
        struct sched_port p[MAX_NPORTS];
        struct tasklet_struct sched_tsk;/* tasklet used to run scheduler */
 };
@@ -259,10 +252,10 @@ static void restart_sched(unsigned long);
  * contention.
  */
 struct sge {
-       struct adapter *adapter;        /* adapter backpointer */
+       struct adapter *adapter;        /* adapter backpointer */
        struct net_device *netdev;      /* netdevice backpointer */
-       struct freelQ   freelQ[SGE_FREELQ_N]; /* buffer free lists */
-       struct respQ    respQ;          /* response Q */
+       struct freelQ   freelQ[SGE_FREELQ_N]; /* buffer free lists */
+       struct respQ    respQ;          /* response Q */
        unsigned long   stopped_tx_queues; /* bitmap of suspended Tx queues */
        unsigned int    rx_pkt_pad;     /* RX padding for L2 packets */
        unsigned int    jumbo_fl;       /* jumbo freelist Q index */
@@ -460,7 +453,7 @@ static struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb,
        if (credits < MAX_SKB_FRAGS + 1)
                goto out;
 
- again:
+again:
        for (i = 0; i < MAX_NPORTS; i++) {
                s->port = ++s->port & (MAX_NPORTS - 1);
                skbq = &s->p[s->port].skbq;
@@ -483,8 +476,8 @@ static struct sk_buff *sched_skb(struct sge *sge, struct sk_buff *skb,
        if (update-- && sched_update_avail(sge))
                goto again;
 
- out:
-       /* If there are more pending skbs, we use the hardware to schedule us
+out:
+       /* If there are more pending skbs, we use the hardware to schedule us
         * again.
         */
        if (s->num && !skb) {
@@ -575,11 +568,10 @@ static int alloc_rx_resources(struct sge *sge, struct sge_params *p)
                q->size = p->freelQ_size[i];
                q->dma_offset = sge->rx_pkt_pad ? 0 : NET_IP_ALIGN;
                size = sizeof(struct freelQ_e) * q->size;
-               q->entries = (struct freelQ_e *)
-                             pci_alloc_consistent(pdev, size, &q->dma_addr);
+               q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr);
                if (!q->entries)
                        goto err_no_mem;
-               memset(q->entries, 0, size);
+
                size = sizeof(struct freelQ_ce) * q->size;
                q->centries = kzalloc(size, GFP_KERNEL);
                if (!q->centries)
@@ -613,11 +605,10 @@ static int alloc_rx_resources(struct sge *sge, struct sge_params *p)
        sge->respQ.size = SGE_RESPQ_E_N;
        sge->respQ.credits = 0;
        size = sizeof(struct respQ_e) * sge->respQ.size;
-       sge->respQ.entries = (struct respQ_e *)
+       sge->respQ.entries =
                pci_alloc_consistent(pdev, size, &sge->respQ.dma_addr);
        if (!sge->respQ.entries)
                goto err_no_mem;
-       memset(sge->respQ.entries, 0, size);
        return 0;
 
 err_no_mem:
@@ -637,20 +628,12 @@ static void free_cmdQ_buffers(struct sge *sge, struct cmdQ *q, unsigned int n)
        q->in_use -= n;
        ce = &q->centries[cidx];
        while (n--) {
-               if (q->sop) {
-                       if (likely(pci_unmap_len(ce, dma_len))) {
-                               pci_unmap_single(pdev,
-                                                pci_unmap_addr(ce, dma_addr),
-                                                pci_unmap_len(ce, dma_len),
-                                                PCI_DMA_TODEVICE);
+               if (likely(pci_unmap_len(ce, dma_len))) {
+                       pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
+                                        pci_unmap_len(ce, dma_len),
+                                        PCI_DMA_TODEVICE);
+                       if (q->sop)
                                q->sop = 0;
-                       }
-               } else {
-                       if (likely(pci_unmap_len(ce, dma_len))) {
-                               pci_unmap_page(pdev, pci_unmap_addr(ce, dma_addr),
-                                              pci_unmap_len(ce, dma_len),
-                                              PCI_DMA_TODEVICE);
-                       }
                }
                if (ce->skb) {
                        dev_kfree_skb_any(ce->skb);
@@ -711,11 +694,10 @@ static int alloc_tx_resources(struct sge *sge, struct sge_params *p)
                q->stop_thres = 0;
                spin_lock_init(&q->lock);
                size = sizeof(struct cmdQ_e) * q->size;
-               q->entries = (struct cmdQ_e *)
-                             pci_alloc_consistent(pdev, size, &q->dma_addr);
+               q->entries = pci_alloc_consistent(pdev, size, &q->dma_addr);
                if (!q->entries)
                        goto err_no_mem;
-               memset(q->entries, 0, size);
+
                size = sizeof(struct cmdQ_ce) * q->size;
                q->centries = kzalloc(size, GFP_KERNEL);
                if (!q->centries)
@@ -770,7 +752,7 @@ void t1_set_vlan_accel(struct adapter *adapter, int on_off)
 static void configure_sge(struct sge *sge, struct sge_params *p)
 {
        struct adapter *ap = sge->adapter;
-       
+
        writel(0, ap->regs + A_SG_CONTROL);
        setup_ring_params(ap, sge->cmdQ[0].dma_addr, sge->cmdQ[0].size,
                          A_SG_CMD0BASELWR, A_SG_CMD0BASEUPR, A_SG_CMD0SIZE);
@@ -850,7 +832,6 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
        struct freelQ_e *e = &q->entries[q->pidx];
        unsigned int dma_len = q->rx_buffer_size - q->dma_offset;
 
-
        while (q->credits < q->size) {
                struct sk_buff *skb;
                dma_addr_t mapping;
@@ -862,6 +843,8 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
                skb_reserve(skb, q->dma_offset);
                mapping = pci_map_single(pdev, skb->data, dma_len,
                                         PCI_DMA_FROMDEVICE);
+               skb_reserve(skb, sge->rx_pkt_pad);
+
                ce->skb = skb;
                pci_unmap_addr_set(ce, dma_addr, mapping);
                pci_unmap_len_set(ce, dma_len, dma_len);
@@ -881,7 +864,6 @@ static void refill_free_list(struct sge *sge, struct freelQ *q)
                }
                q->credits++;
        }
-
 }
 
 /*
@@ -1041,6 +1023,10 @@ static void recycle_fl_buf(struct freelQ *fl, int idx)
        }
 }
 
+static int copybreak __read_mostly = 256;
+module_param(copybreak, int, 0);
+MODULE_PARM_DESC(copybreak, "Receive copy threshold");
+
 /**
  *     get_packet - return the next ingress packet buffer
  *     @pdev: the PCI device that received the packet
@@ -1060,45 +1046,42 @@ static void recycle_fl_buf(struct freelQ *fl, int idx)
  *     be copied but there is no memory for the copy.
  */
 static inline struct sk_buff *get_packet(struct pci_dev *pdev,
-                                        struct freelQ *fl, unsigned int len,
-                                        int dma_pad, int skb_pad,
-                                        unsigned int copy_thres,
-                                        unsigned int drop_thres)
+                                        struct freelQ *fl, unsigned int len)
 {
        struct sk_buff *skb;
-       struct freelQ_ce *ce = &fl->centries[fl->cidx];
+       const struct freelQ_ce *ce = &fl->centries[fl->cidx];
 
-       if (len < copy_thres) {
-               skb = alloc_skb(len + skb_pad, GFP_ATOMIC);
-               if (likely(skb != NULL)) {
-                       skb_reserve(skb, skb_pad);
-                       skb_put(skb, len);
-                       pci_dma_sync_single_for_cpu(pdev,
-                                           pci_unmap_addr(ce, dma_addr),
-                                           pci_unmap_len(ce, dma_len),
-                                           PCI_DMA_FROMDEVICE);
-                       memcpy(skb->data, ce->skb->data + dma_pad, len);
-                       pci_dma_sync_single_for_device(pdev,
-                                           pci_unmap_addr(ce, dma_addr),
-                                           pci_unmap_len(ce, dma_len),
-                                           PCI_DMA_FROMDEVICE);
-               } else if (!drop_thres)
+       if (len < copybreak) {
+               skb = alloc_skb(len + 2, GFP_ATOMIC);
+               if (!skb)
                        goto use_orig_buf;
 
+               skb_reserve(skb, 2);    /* align IP header */
+               skb_put(skb, len);
+               pci_dma_sync_single_for_cpu(pdev,
+                                           pci_unmap_addr(ce, dma_addr),
+                                           pci_unmap_len(ce, dma_len),
+                                           PCI_DMA_FROMDEVICE);
+               memcpy(skb->data, ce->skb->data, len);
+               pci_dma_sync_single_for_device(pdev,
+                                              pci_unmap_addr(ce, dma_addr),
+                                              pci_unmap_len(ce, dma_len),
+                                              PCI_DMA_FROMDEVICE);
                recycle_fl_buf(fl, fl->cidx);
                return skb;
        }
 
-       if (fl->credits < drop_thres) {
+use_orig_buf:
+       if (fl->credits < 2) {
                recycle_fl_buf(fl, fl->cidx);
                return NULL;
        }
 
-use_orig_buf:
        pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr),
                         pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE);
        skb = ce->skb;
-       skb_reserve(skb, dma_pad);
+       prefetch(skb->data);
+
        skb_put(skb, len);
        return skb;
 }
@@ -1137,6 +1120,7 @@ static void unexpected_offload(struct adapter *adapter, struct freelQ *fl)
 static inline unsigned int compute_large_page_tx_descs(struct sk_buff *skb)
 {
        unsigned int count = 0;
+
        if (PAGE_SIZE > SGE_TX_DESC_MAX_PLEN) {
                unsigned int nfrags = skb_shinfo(skb)->nr_frags;
                unsigned int i, len = skb->len - skb->data_len;
@@ -1343,7 +1327,7 @@ static void restart_sched(unsigned long arg)
        while ((skb = sched_skb(sge, NULL, credits)) != NULL) {
                unsigned int genbit, pidx, count;
                count = 1 + skb_shinfo(skb)->nr_frags;
-                       count += compute_large_page_tx_descs(skb);
+               count += compute_large_page_tx_descs(skb);
                q->in_use += count;
                genbit = q->genbit;
                pidx = q->pidx;
@@ -1375,27 +1359,25 @@ static void restart_sched(unsigned long arg)
  *
  *     Process an ingress ethernet pakcet and deliver it to the stack.
  */
-static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
+static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
 {
        struct sk_buff *skb;
-       struct cpl_rx_pkt *p;
+       const struct cpl_rx_pkt *p;
        struct adapter *adapter = sge->adapter;
        struct sge_port_stats *st;
 
-       skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad,
-                        sge->rx_pkt_pad, 2, SGE_RX_COPY_THRES,
-                        SGE_RX_DROP_THRES);
+       skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad);
        if (unlikely(!skb)) {
                sge->stats.rx_drops++;
-               return 0;
+               return;
        }
 
-       p = (struct cpl_rx_pkt *)skb->data;
-       skb_pull(skb, sizeof(*p));
+       p = (const struct cpl_rx_pkt *) skb->data;
        if (p->iff >= adapter->params.nports) {
                kfree_skb(skb);
-               return 0;
+               return;
        }
+       __skb_pull(skb, sizeof(*p));
 
        skb->dev = adapter->port[p->iff].dev;
        skb->dev->last_rx = jiffies;
@@ -1427,7 +1409,6 @@ static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len)
                netif_rx(skb);
 #endif
        }
-       return 0;
 }
 
 /*
@@ -1448,29 +1429,28 @@ static inline int enough_free_Tx_descs(const struct cmdQ *q)
 static void restart_tx_queues(struct sge *sge)
 {
        struct adapter *adap = sge->adapter;
+       int i;
 
-       if (enough_free_Tx_descs(&sge->cmdQ[0])) {
-               int i;
+       if (!enough_free_Tx_descs(&sge->cmdQ[0]))
+               return;
 
-               for_each_port(adap, i) {
-                       struct net_device *nd = adap->port[i].dev;
+       for_each_port(adap, i) {
+               struct net_device *nd = adap->port[i].dev;
 
-                       if (test_and_clear_bit(nd->if_port,
-                                              &sge->stopped_tx_queues) &&
-                           netif_running(nd)) {
-                               sge->stats.cmdQ_restarted[2]++;
-                               netif_wake_queue(nd);
-                       }
+               if (test_and_clear_bit(nd->if_port, &sge->stopped_tx_queues) &&
+                   netif_running(nd)) {
+                       sge->stats.cmdQ_restarted[2]++;
+                       netif_wake_queue(nd);
                }
        }
 }
 
 /*
- * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0 
+ * update_tx_info is called from the interrupt handler/NAPI to return cmdQ0
  * information.
  */
-static unsigned int update_tx_info(struct adapter *adapter, 
-                                         unsigned int flags, 
+static unsigned int update_tx_info(struct adapter *adapter,
+                                         unsigned int flags,
                                          unsigned int pr0)
 {
        struct sge *sge = adapter->sge;
@@ -1510,29 +1490,30 @@ static int process_responses(struct adapter *adapter, int budget)
        struct sge *sge = adapter->sge;
        struct respQ *q = &sge->respQ;
        struct respQ_e *e = &q->entries[q->cidx];
-       int budget_left = budget;
+       int done = 0;
        unsigned int flags = 0;
        unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0};
-       
 
-       while (likely(budget_left && e->GenerationBit == q->genbit)) {
+       while (done < budget && e->GenerationBit == q->genbit) {
                flags |= e->Qsleeping;
-               
+
                cmdq_processed[0] += e->Cmdq0CreditReturn;
                cmdq_processed[1] += e->Cmdq1CreditReturn;
-               
+
                /* We batch updates to the TX side to avoid cacheline
                 * ping-pong of TX state information on MP where the sender
                 * might run on a different CPU than this function...
                 */
-               if (unlikely(flags & F_CMDQ0_ENABLE || cmdq_processed[0] > 64)) {
+               if (unlikely((flags & F_CMDQ0_ENABLE) || cmdq_processed[0] > 64)) {
                        flags = update_tx_info(adapter, flags, cmdq_processed[0]);
                        cmdq_processed[0] = 0;
                }
+
                if (unlikely(cmdq_processed[1] > 16)) {
                        sge->cmdQ[1].processed += cmdq_processed[1];
                        cmdq_processed[1] = 0;
                }
+
                if (likely(e->DataValid)) {
                        struct freelQ *fl = &sge->freelQ[e->FreelistQid];
 
@@ -1542,12 +1523,16 @@ static int process_responses(struct adapter *adapter, int budget)
                        else
                                sge_rx(sge, fl, e->BufferLength);
 
+                       ++done;
+
                        /*
                         * Note: this depends on each packet consuming a
                         * single free-list buffer; cf. the BUG above.
                         */
                        if (++fl->cidx == fl->size)
                                fl->cidx = 0;
+                       prefetch(fl->centries[fl->cidx].skb);
+
                        if (unlikely(--fl->credits <
                                     fl->size - SGE_FREEL_REFILL_THRESH))
                                refill_free_list(sge, fl);
@@ -1566,14 +1551,20 @@ static int process_responses(struct adapter *adapter, int budget)
                        writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT);
                        q->credits = 0;
                }
-               --budget_left;
        }
 
-       flags = update_tx_info(adapter, flags, cmdq_processed[0]); 
+       flags = update_tx_info(adapter, flags, cmdq_processed[0]);
        sge->cmdQ[1].processed += cmdq_processed[1];
 
-       budget -= budget_left;
-       return budget;
+       return done;
+}
+
+static inline int responses_pending(const struct adapter *adapter)
+{
+       const struct respQ *Q = &adapter->sge->respQ;
+       const struct respQ_e *e = &Q->entries[Q->cidx];
+
+       return (e->GenerationBit == Q->genbit);
 }
 
 #ifdef CONFIG_CHELSIO_T1_NAPI
@@ -1585,19 +1576,25 @@ static int process_responses(struct adapter *adapter, int budget)
  * which the caller must ensure is a valid pure response.  Returns 1 if it
  * encounters a valid data-carrying response, 0 otherwise.
  */
-static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
+static int process_pure_responses(struct adapter *adapter)
 {
        struct sge *sge = adapter->sge;
        struct respQ *q = &sge->respQ;
+       struct respQ_e *e = &q->entries[q->cidx];
+       const struct freelQ *fl = &sge->freelQ[e->FreelistQid];
        unsigned int flags = 0;
        unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0};
 
+       prefetch(fl->centries[fl->cidx].skb);
+       if (e->DataValid)
+               return 1;
+
        do {
                flags |= e->Qsleeping;
 
                cmdq_processed[0] += e->Cmdq0CreditReturn;
                cmdq_processed[1] += e->Cmdq1CreditReturn;
-               
+
                e++;
                if (unlikely(++q->cidx == q->size)) {
                        q->cidx = 0;
@@ -1613,7 +1610,7 @@ static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
                sge->stats.pure_rsps++;
        } while (e->GenerationBit == q->genbit && !e->DataValid);
 
-       flags = update_tx_info(adapter, flags, cmdq_processed[0]); 
+       flags = update_tx_info(adapter, flags, cmdq_processed[0]);
        sge->cmdQ[1].processed += cmdq_processed[1];
 
        return e->GenerationBit == q->genbit;
@@ -1627,23 +1624,20 @@ static int process_pure_responses(struct adapter *adapter, struct respQ_e *e)
 int t1_poll(struct net_device *dev, int *budget)
 {
        struct adapter *adapter = dev->priv;
-       int effective_budget = min(*budget, dev->quota);
-       int work_done = process_responses(adapter, effective_budget);
+       int work_done;
 
+       work_done = process_responses(adapter, min(*budget, dev->quota));
        *budget -= work_done;
        dev->quota -= work_done;
 
-       if (work_done >= effective_budget)
+       if (unlikely(responses_pending(adapter)))
                return 1;
 
-       spin_lock_irq(&adapter->async_lock);
-       __netif_rx_complete(dev);
+       netif_rx_complete(dev);
        writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
-       writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA,
-              adapter->regs + A_PL_ENABLE);
-       spin_unlock_irq(&adapter->async_lock);
 
        return 0;
+
 }
 
 /*
@@ -1652,44 +1646,33 @@ int t1_poll(struct net_device *dev, int *budget)
 irqreturn_t t1_interrupt(int irq, void *data)
 {
        struct adapter *adapter = data;
-       struct net_device *dev = adapter->sge->netdev;
        struct sge *sge = adapter->sge;
-       u32 cause;
-       int handled = 0;
+       int handled;
 
-       cause = readl(adapter->regs + A_PL_CAUSE);
-       if (cause == 0 || cause == ~0)
-               return IRQ_NONE;
+       if (likely(responses_pending(adapter))) {
+               struct net_device *dev = sge->netdev;
 
-       spin_lock(&adapter->async_lock);
-       if (cause & F_PL_INTR_SGE_DATA) {
-               struct respQ *q = &adapter->sge->respQ;
-               struct respQ_e *e = &q->entries[q->cidx];
-
-               handled = 1;
-               writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
-
-               if (e->GenerationBit == q->genbit &&
-                   __netif_rx_schedule_prep(dev)) {
-                       if (e->DataValid || process_pure_responses(adapter, e)) {
-                               /* mask off data IRQ */
-                               writel(adapter->slow_intr_mask,
-                                      adapter->regs + A_PL_ENABLE);
-                               __netif_rx_schedule(sge->netdev);
-                               goto unlock;
-                       }
-                       /* no data, no NAPI needed */
-                       netif_poll_enable(dev);
+               writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
 
+               if (__netif_rx_schedule_prep(dev)) {
+                       if (process_pure_responses(adapter))
+                               __netif_rx_schedule(dev);
+                       else {
+                               /* no data, no NAPI needed */
+                               writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING);
+                               netif_poll_enable(dev); /* undo schedule_prep */
+                       }
                }
-               writel(q->cidx, adapter->regs + A_SG_SLEEPING);
-       } else
-               handled = t1_slow_intr_handler(adapter);
+               return IRQ_HANDLED;
+       }
+
+       spin_lock(&adapter->async_lock);
+       handled = t1_slow_intr_handler(adapter);
+       spin_unlock(&adapter->async_lock);
 
        if (!handled)
                sge->stats.unhandled_irqs++;
-unlock:
-       spin_unlock(&adapter->async_lock);
+
        return IRQ_RETVAL(handled != 0);
 }
 
@@ -1712,17 +1695,13 @@ unlock:
 irqreturn_t t1_interrupt(int irq, void *cookie)
 {
        int work_done;
-       struct respQ_e *e;
        struct adapter *adapter = cookie;
-       struct respQ *Q = &adapter->sge->respQ;
 
        spin_lock(&adapter->async_lock);
-       e = &Q->entries[Q->cidx];
-       prefetch(e);
 
        writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE);
 
-       if (likely(e->GenerationBit == Q->genbit))
+       if (likely(responses_pending(adapter)))
                work_done = process_responses(adapter, -1);
        else
                work_done = t1_slow_intr_handler(adapter);
@@ -1796,7 +1775,7 @@ static int t1_sge_tx(struct sk_buff *skb, struct adapter *adapter,
         * through the scheduler.
         */
        if (sge->tx_sched && !qid && skb->dev) {
-       use_sched:
+use_sched:
                use_sched_skb = 1;
                /* Note that the scheduler might return a different skb than
                 * the one passed in.
@@ -1900,7 +1879,7 @@ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
                cpl = (struct cpl_tx_pkt *)hdr;
        } else {
                /*
-                * Packets shorter than ETH_HLEN can break the MAC, drop them
+                * Packets shorter than ETH_HLEN can break the MAC, drop them
                 * early.  Also, we may get oversized packets because some
                 * parts of the kernel don't handle our unusual hard_header_len
                 * right, drop those too.
@@ -1984,9 +1963,9 @@ send:
         * then silently discard to avoid leak.
         */
        if (unlikely(ret != NETDEV_TX_OK && skb != orig_skb)) {
-               dev_kfree_skb_any(skb);
+               dev_kfree_skb_any(skb);
                ret = NETDEV_TX_OK;
-       }
+       }
        return ret;
 }
 
@@ -2099,31 +2078,35 @@ static void espibug_workaround_t204(unsigned long data)
 
        if (adapter->open_device_map & PORT_MASK) {
                int i;
-               if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0) {
+
+               if (t1_espi_get_mon_t204(adapter, &(seop[0]), 0) < 0)
                        return;
-               }
+
                for (i = 0; i < nports; i++) {
-                       struct sk_buff *skb = sge->espibug_skb[i];
-                       if ( (netif_running(adapter->port[i].dev)) &&
-                            !(netif_queue_stopped(adapter->port[i].dev)) &&
-                            (seop[i] && ((seop[i] & 0xfff) == 0)) &&
-                            skb ) {
-                               if (!skb->cb[0]) {
-                                       u8 ch_mac_addr[ETH_ALEN] =
-                                       {0x0, 0x7, 0x43, 0x0, 0x0, 0x0};
-                                       memcpy(skb->data + sizeof(struct cpl_tx_pkt),
-                                       ch_mac_addr, ETH_ALEN);
-                                       memcpy(skb->data + skb->len - 10,
-                                               ch_mac_addr, ETH_ALEN);
-                                       skb->cb[0] = 0xff;
-                               }
-
-                               /* bump the reference count to avoid freeing of
-                                * the skb once the DMA has completed.
-                                */
-                               skb = skb_get(skb);
-                               t1_sge_tx(skb, adapter, 0, adapter->port[i].dev);
+                       struct sk_buff *skb = sge->espibug_skb[i];
+
+                       if (!netif_running(adapter->port[i].dev) ||
+                           netif_queue_stopped(adapter->port[i].dev) ||
+                           !seop[i] || ((seop[i] & 0xfff) != 0) || !skb)
+                               continue;
+
+                       if (!skb->cb[0]) {
+                               u8 ch_mac_addr[ETH_ALEN] = {
+                                       0x0, 0x7, 0x43, 0x0, 0x0, 0x0
+                               };
+
+                               memcpy(skb->data + sizeof(struct cpl_tx_pkt),
+                                       ch_mac_addr, ETH_ALEN);
+                               memcpy(skb->data + skb->len - 10,
+                                       ch_mac_addr, ETH_ALEN);
+                               skb->cb[0] = 0xff;
                        }
+
+                       /* bump the reference count to avoid freeing of
+                        * the skb once the DMA has completed.
+                        */
+                       skb = skb_get(skb);
+                       t1_sge_tx(skb, adapter, 0, adapter->port[i].dev);
                }
        }
        mod_timer(&sge->espibug_timer, jiffies + sge->espibug_timeout);
@@ -2192,9 +2175,8 @@ struct sge * __devinit t1_sge_create(struct adapter *adapter,
                if (adapter->params.nports > 1) {
                        tx_sched_init(sge);
                        sge->espibug_timer.function = espibug_workaround_t204;
-               } else {
+               } else
                        sge->espibug_timer.function = espibug_workaround;
-               }
                sge->espibug_timer.data = (unsigned long)sge->adapter;
 
                sge->espibug_timeout = 1;
@@ -2202,7 +2184,7 @@ struct sge * __devinit t1_sge_create(struct adapter *adapter,
                if (adapter->params.nports > 1)
                        sge->espibug_timeout = HZ/100;
        }
-        
+
 
        p->cmdQ_size[0] = SGE_CMDQ0_E_N;
        p->cmdQ_size[1] = SGE_CMDQ1_E_N;
index 22ed9a3..c2522cd 100644 (file)
@@ -223,13 +223,13 @@ static int fpga_slow_intr(adapter_t *adapter)
                t1_sge_intr_error_handler(adapter->sge);
 
        if (cause & FPGA_PCIX_INTERRUPT_GMAC)
-                fpga_phy_intr_handler(adapter);
+               fpga_phy_intr_handler(adapter);
 
        if (cause & FPGA_PCIX_INTERRUPT_TP) {
-                /*
+               /*
                 * FPGA doesn't support MC4 interrupts and it requires
                 * this odd layer of indirection for MC5.
-                 */
+                */
                u32 tp_cause = readl(adapter->regs + FPGA_TP_ADDR_INTERRUPT_CAUSE);
 
                /* Clear TP interrupt */
@@ -262,8 +262,7 @@ static int mi1_wait_until_ready(adapter_t *adapter, int mi1_reg)
                        udelay(10);
        } while (busy && --attempts);
        if (busy)
-               CH_ALERT("%s: MDIO operation timed out\n",
-                        adapter->name);
+               CH_ALERT("%s: MDIO operation timed out\n", adapter->name);
        return busy;
 }
 
@@ -605,22 +604,23 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
 
        switch (board_info(adapter)->board) {
 #ifdef CONFIG_CHELSIO_T1_1G
-        case CHBT_BOARD_CHT204:
-        case CHBT_BOARD_CHT204E:
-        case CHBT_BOARD_CHN204:
-        case CHBT_BOARD_CHT204V: {
-                int i, port_bit;
+       case CHBT_BOARD_CHT204:
+       case CHBT_BOARD_CHT204E:
+       case CHBT_BOARD_CHN204:
+       case CHBT_BOARD_CHT204V: {
+               int i, port_bit;
                for_each_port(adapter, i) {
                        port_bit = i + 1;
-                       if (!(cause & (1 << port_bit))) continue;
+                       if (!(cause & (1 << port_bit)))
+                               continue;
 
-                       phy = adapter->port[i].phy;
+                       phy = adapter->port[i].phy;
                        phy_cause = phy->ops->interrupt_handler(phy);
                        if (phy_cause & cphy_cause_link_change)
                                t1_link_changed(adapter, i);
                }
-                break;
-        }
+               break;
+       }
        case CHBT_BOARD_CHT101:
                if (cause & ELMER0_GP_BIT1) { /* Marvell 88E1111 interrupt */
                        phy = adapter->port[0].phy;
@@ -631,13 +631,13 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
                break;
        case CHBT_BOARD_7500: {
                int p;
-               /*
+               /*
                 * Elmer0's interrupt cause isn't useful here because there is
                 * only one bit that can be set for all 4 ports.  This means
                 * we are forced to check every PHY's interrupt status
                 * register to see who initiated the interrupt.
-                */
-               for_each_port(adapter, p) {
+                */
+               for_each_port(adapter, p) {
                        phy = adapter->port[p].phy;
                        phy_cause = phy->ops->interrupt_handler(phy);
                        if (phy_cause & cphy_cause_link_change)
@@ -658,7 +658,7 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
                break;
        case CHBT_BOARD_8000:
        case CHBT_BOARD_CHT110:
-               CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n",
+               CH_DBG(adapter, INTR, "External interrupt cause 0x%x\n",
                       cause);
                if (cause & ELMER0_GP_BIT1) {        /* PMC3393 INTB */
                        struct cmac *mac = adapter->port[0].mac;
@@ -670,9 +670,9 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
 
                        t1_tpi_read(adapter,
                                        A_ELMER0_GPI_STAT, &mod_detect);
-                       CH_MSG(adapter, INFO, LINK, "XPAK %s\n",
+                       CH_MSG(adapter, INFO, LINK, "XPAK %s\n",
                               mod_detect ? "removed" : "inserted");
-               }
+               }
                break;
 #ifdef CONFIG_CHELSIO_T1_COUGAR
        case CHBT_BOARD_COUGAR:
@@ -688,7 +688,8 @@ int t1_elmer0_ext_intr_handler(adapter_t *adapter)
 
                        for_each_port(adapter, i) {
                                port_bit = i ? i + 1 : 0;
-                               if (!(cause & (1 << port_bit))) continue;
+                               if (!(cause & (1 << port_bit)))
+                                       continue;
 
                                phy = adapter->port[i].phy;
                                phy_cause = phy->ops->interrupt_handler(phy);
@@ -755,7 +756,7 @@ void t1_interrupts_disable(adapter_t* adapter)
 
        /* Disable PCIX & external chip interrupts. */
        if (t1_is_asic(adapter))
-               writel(0, adapter->regs + A_PL_ENABLE);
+               writel(0, adapter->regs + A_PL_ENABLE);
 
        /* PCI-X interrupts */
        pci_write_config_dword(adapter->pdev, A_PCICFG_INTR_ENABLE, 0);
@@ -830,11 +831,11 @@ int t1_slow_intr_handler(adapter_t *adapter)
 /* Power sequencing is a work-around for Intel's XPAKs. */
 static void power_sequence_xpak(adapter_t* adapter)
 {
-       u32 mod_detect;
-       u32 gpo;
+       u32 mod_detect;
+       u32 gpo;
 
-       /* Check for XPAK */
-       t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);
+       /* Check for XPAK */
+       t1_tpi_read(adapter, A_ELMER0_GPI_STAT, &mod_detect);
        if (!(ELMER0_GP_BIT5 & mod_detect)) {
                /* XPAK is present */
                t1_tpi_read(adapter, A_ELMER0_GPO, &gpo);
@@ -877,31 +878,31 @@ static int board_init(adapter_t *adapter, const struct board_info *bi)
        case CHBT_BOARD_N210:
        case CHBT_BOARD_CHT210:
        case CHBT_BOARD_COUGAR:
-               t1_tpi_par(adapter, 0xf);
-               t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
+               t1_tpi_par(adapter, 0xf);
+               t1_tpi_write(adapter, A_ELMER0_GPO, 0x800);
                break;
        case CHBT_BOARD_CHT110:
-               t1_tpi_par(adapter, 0xf);
-               t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800);
+               t1_tpi_par(adapter, 0xf);
+               t1_tpi_write(adapter, A_ELMER0_GPO, 0x1800);
 
-               /* TBD XXX Might not need.  This fixes a problem
-                *         described in the Intel SR XPAK errata.
-                */
-               power_sequence_xpak(adapter);
+               /* TBD XXX Might not need.  This fixes a problem
+                *         described in the Intel SR XPAK errata.
+                */
+               power_sequence_xpak(adapter);
                break;
 #ifdef CONFIG_CHELSIO_T1_1G
-    case CHBT_BOARD_CHT204E:
-                       /* add config space write here */
+       case CHBT_BOARD_CHT204E:
+               /* add config space write here */
        case CHBT_BOARD_CHT204:
        case CHBT_BOARD_CHT204V:
        case CHBT_BOARD_CHN204:
-                t1_tpi_par(adapter, 0xf);
-                t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);
-                break;
+               t1_tpi_par(adapter, 0xf);
+               t1_tpi_write(adapter, A_ELMER0_GPO, 0x804);
+               break;
        case CHBT_BOARD_CHT101:
        case CHBT_BOARD_7500:
-               t1_tpi_par(adapter, 0xf);
-               t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);
+               t1_tpi_par(adapter, 0xf);
+               t1_tpi_write(adapter, A_ELMER0_GPO, 0x1804);
                break;
 #endif
        }
@@ -941,7 +942,7 @@ int t1_init_hw_modules(adapter_t *adapter)
                goto out_err;
 
        err = 0;
- out_err:
+out_err:
        return err;
 }
 
@@ -983,7 +984,7 @@ void t1_free_sw_modules(adapter_t *adapter)
        if (adapter->espi)
                t1_espi_destroy(adapter->espi);
 #ifdef CONFIG_CHELSIO_T1_COUGAR
-        if (adapter->cspi)
+       if (adapter->cspi)
                t1_cspi_destroy(adapter->cspi);
 #endif
 }
@@ -1010,7 +1011,7 @@ static void __devinit init_link_config(struct link_config *lc,
                CH_ERR("%s: CSPI initialization failed\n",
                       adapter->name);
                goto error;
-        }
+       }
 #endif
 
 /*
index 0ca0b6e..6222d58 100644 (file)
@@ -17,39 +17,36 @@ struct petp {
 static void tp_init(adapter_t * ap, const struct tp_params *p,
                    unsigned int tp_clk)
 {
-       if (t1_is_asic(ap)) {
-               u32 val;
-
-               val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM |
-                   F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET;
-               if (!p->pm_size)
-                       val |= F_OFFLOAD_DISABLE;
-               else
-                       val |= F_TP_IN_ESPI_CHECK_IP_CSUM |
-                           F_TP_IN_ESPI_CHECK_TCP_CSUM;
-               writel(val, ap->regs + A_TP_IN_CONFIG);
-               writel(F_TP_OUT_CSPI_CPL |
-                      F_TP_OUT_ESPI_ETHERNET |
-                      F_TP_OUT_ESPI_GENERATE_IP_CSUM |
-                      F_TP_OUT_ESPI_GENERATE_TCP_CSUM,
-                      ap->regs + A_TP_OUT_CONFIG);
-               writel(V_IP_TTL(64) |
-                      F_PATH_MTU /* IP DF bit */  |
-                      V_5TUPLE_LOOKUP(p->use_5tuple_mode) |
-                      V_SYN_COOKIE_PARAMETER(29),
-                      ap->regs + A_TP_GLOBAL_CONFIG);
-               /*
-                * Enable pause frame deadlock prevention.
-                */
-               if (is_T2(ap) && ap->params.nports > 1) {
-                       u32 drop_ticks = DROP_MSEC * (tp_clk / 1000);
-
-                       writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR |
-                              V_DROP_TICKS_CNT(drop_ticks) |
-                              V_NUM_PKTS_DROPPED(DROP_PKTS_CNT),
-                              ap->regs + A_TP_TX_DROP_CONFIG);
-               }
+       u32 val;
 
+       if (!t1_is_asic(ap))
+               return;
+
+       val = F_TP_IN_CSPI_CPL | F_TP_IN_CSPI_CHECK_IP_CSUM |
+               F_TP_IN_CSPI_CHECK_TCP_CSUM | F_TP_IN_ESPI_ETHERNET;
+       if (!p->pm_size)
+               val |= F_OFFLOAD_DISABLE;
+       else
+               val |= F_TP_IN_ESPI_CHECK_IP_CSUM | F_TP_IN_ESPI_CHECK_TCP_CSUM;
+       writel(val, ap->regs + A_TP_IN_CONFIG);
+       writel(F_TP_OUT_CSPI_CPL |
+              F_TP_OUT_ESPI_ETHERNET |
+              F_TP_OUT_ESPI_GENERATE_IP_CSUM |
+              F_TP_OUT_ESPI_GENERATE_TCP_CSUM, ap->regs + A_TP_OUT_CONFIG);
+       writel(V_IP_TTL(64) |
+              F_PATH_MTU /* IP DF bit */  |
+              V_5TUPLE_LOOKUP(p->use_5tuple_mode) |
+              V_SYN_COOKIE_PARAMETER(29), ap->regs + A_TP_GLOBAL_CONFIG);
+       /*
+        * Enable pause frame deadlock prevention.
+        */
+       if (is_T2(ap) && ap->params.nports > 1) {
+               u32 drop_ticks = DROP_MSEC * (tp_clk / 1000);
+
+               writel(F_ENABLE_TX_DROP | F_ENABLE_TX_ERROR |
+                      V_DROP_TICKS_CNT(drop_ticks) |
+                      V_NUM_PKTS_DROPPED(DROP_PKTS_CNT),
+                      ap->regs + A_TP_TX_DROP_CONFIG);
        }
 }
 
@@ -61,6 +58,7 @@ void t1_tp_destroy(struct petp *tp)
 struct petp *__devinit t1_tp_create(adapter_t * adapter, struct tp_params *p)
 {
        struct petp *tp = kzalloc(sizeof(*tp), GFP_KERNEL);
+
        if (!tp)
                return NULL;
 
index 85dc3b1..534ffa0 100644 (file)
@@ -226,22 +226,21 @@ static void run_table(adapter_t *adapter, struct init_table *ib, int len)
                if (ib[i].addr == INITBLOCK_SLEEP) {
                        udelay( ib[i].data );
                        CH_ERR("sleep %d us\n",ib[i].data);
-               } else {
+               } else
                        vsc_write( adapter, ib[i].addr, ib[i].data );
-               }
        }
 }
 
 static int bist_rd(adapter_t *adapter, int moduleid, int address)
 {
-       int data=0;
-       u32 result=0;
-
-       if(     (address != 0x0) &&
-               (address != 0x1) &&
-               (address != 0x2) &&
-               (address != 0xd) &&
-               (address != 0xe))
+       int data = 0;
+       u32 result = 0;
+
+       if ((address != 0x0) &&
+           (address != 0x1) &&
+           (address != 0x2) &&
+           (address != 0xd) &&
+           (address != 0xe))
                        CH_ERR("No bist address: 0x%x\n", address);
 
        data = ((0x00 << 24) | ((address & 0xff) << 16) | (0x00 << 8) |
@@ -251,27 +250,27 @@ static int bist_rd(adapter_t *adapter, int moduleid, int address)
        udelay(10);
 
        vsc_read(adapter, REG_RAM_BIST_RESULT, &result);
-       if((result & (1<<9)) != 0x0)
+       if ((result & (1 << 9)) != 0x0)
                CH_ERR("Still in bist read: 0x%x\n", result);
-       else if((result & (1<<8)) != 0x0)
+       else if ((result & (1 << 8)) != 0x0)
                CH_ERR("bist read error: 0x%x\n", result);
 
-       return(result & 0xff);
+       return (result & 0xff);
 }
 
 static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
 {
-       int data=0;
-       u32 result=0;
-
-       if(     (address != 0x0) &&
-               (address != 0x1) &&
-               (address != 0x2) &&
-               (address != 0xd) &&
-               (address != 0xe))
+       int data = 0;
+       u32 result = 0;
+
+       if ((address != 0x0) &&
+           (address != 0x1) &&
+           (address != 0x2) &&
+           (address != 0xd) &&
+           (address != 0xe))
                        CH_ERR("No bist address: 0x%x\n", address);
 
-       if( value>255 )
+       if (value > 255)
                CH_ERR("Suspicious write out of range value: 0x%x\n", value);
 
        data = ((0x01 << 24) | ((address & 0xff) << 16) | (value << 8) |
@@ -281,12 +280,12 @@ static int bist_wr(adapter_t *adapter, int moduleid, int address, int value)
        udelay(5);
 
        vsc_read(adapter, REG_RAM_BIST_CMD, &result);
-       if((result & (1<<27)) != 0x0)
+       if ((result & (1 << 27)) != 0x0)
                CH_ERR("Still in bist write: 0x%x\n", result);
-       else if((result & (1<<26)) != 0x0)
+       else if ((result & (1 << 26)) != 0x0)
                CH_ERR("bist write error: 0x%x\n", result);
 
-       return(0);
+       return 0;
 }
 
 static int run_bist(adapter_t *adapter, int moduleid)
@@ -295,7 +294,7 @@ static int run_bist(adapter_t *adapter, int moduleid)
        (void) bist_wr(adapter,moduleid, 0x00, 0x02);
        (void) bist_wr(adapter,moduleid, 0x01, 0x01);
 
-       return(0);
+       return 0;
 }
 
 static int check_bist(adapter_t *adapter, int moduleid)
@@ -309,27 +308,26 @@ static int check_bist(adapter_t *adapter, int moduleid)
        if ((result & 3) != 0x3)
                CH_ERR("Result: 0x%x  BIST error in ram %d, column: 0x%04x\n",
                        result, moduleid, column);
-       return(0);
+       return 0;
 }
 
 static int enable_mem(adapter_t *adapter, int moduleid)
 {
        /*enable mem*/
        (void) bist_wr(adapter,moduleid, 0x00, 0x00);
-       return(0);
+       return 0;
 }
 
 static int run_bist_all(adapter_t *adapter)
 {
-       int port=0;
-       u32 val=0;
+       int port = 0;
+       u32 val = 0;
 
        vsc_write(adapter, REG_MEM_BIST, 0x5);
        vsc_read(adapter, REG_MEM_BIST, &val);
 
-       for(port=0; port<12; port++){
+       for (port = 0; port < 12; port++)
                vsc_write(adapter, REG_DEV_SETUP(port), 0x0);
-       }
 
        udelay(300);
        vsc_write(adapter, REG_SPI4_MISC, 0x00040409);
@@ -352,13 +350,13 @@ static int run_bist_all(adapter_t *adapter)
        udelay(300);
        vsc_write(adapter, REG_SPI4_MISC, 0x60040400);
        udelay(300);
-       for(port=0; port<12; port++){
+       for (port = 0; port < 12; port++)
                vsc_write(adapter, REG_DEV_SETUP(port), 0x1);
-       }
+
        udelay(300);
        vsc_write(adapter, REG_MEM_BIST, 0x0);
        mdelay(10);
-       return(0);
+       return 0;
 }
 
 static int mac_intr_handler(struct cmac *mac)
@@ -591,40 +589,46 @@ static void rmon_update(struct cmac *mac, unsigned int addr, u64 *stat)
 
 static void port_stats_update(struct cmac *mac)
 {
-       int port = mac->instance->index;
+       struct {
+               unsigned int reg;
+               unsigned int offset;
+       } hw_stats[] = {
+
+#define HW_STAT(reg, stat_name) \
+       { reg, (&((struct cmac_statistics *)NULL)->stat_name) - (u64 *)NULL }
+
+               /* Rx stats */
+               HW_STAT(RxUnicast, RxUnicastFramesOK),
+               HW_STAT(RxMulticast, RxMulticastFramesOK),
+               HW_STAT(RxBroadcast, RxBroadcastFramesOK),
+               HW_STAT(Crc, RxFCSErrors),
+               HW_STAT(RxAlignment, RxAlignErrors),
+               HW_STAT(RxOversize, RxFrameTooLongErrors),
+               HW_STAT(RxPause, RxPauseFrames),
+               HW_STAT(RxJabbers, RxJabberErrors),
+               HW_STAT(RxFragments, RxRuntErrors),
+               HW_STAT(RxUndersize, RxRuntErrors),
+               HW_STAT(RxSymbolCarrier, RxSymbolErrors),
+               HW_STAT(RxSize1519ToMax, RxJumboFramesOK),
+
+               /* Tx stats (skip collision stats as we are full-duplex only) */
+               HW_STAT(TxUnicast, TxUnicastFramesOK),
+               HW_STAT(TxMulticast, TxMulticastFramesOK),
+               HW_STAT(TxBroadcast, TxBroadcastFramesOK),
+               HW_STAT(TxPause, TxPauseFrames),
+               HW_STAT(TxUnderrun, TxUnderrun),
+               HW_STAT(TxSize1519ToMax, TxJumboFramesOK),
+       }, *p = hw_stats;
+       unsigned int port = mac->instance->index;
+       u64 *stats = (u64 *)&mac->stats;
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(hw_stats); i++)
+               rmon_update(mac, CRA(0x4, port, p->reg), stats + p->offset);
 
-       /* Rx stats */
+       rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK);
        rmon_update(mac, REG_RX_OK_BYTES(port), &mac->stats.RxOctetsOK);
        rmon_update(mac, REG_RX_BAD_BYTES(port), &mac->stats.RxOctetsBad);
-       rmon_update(mac, REG_RX_UNICAST(port), &mac->stats.RxUnicastFramesOK);
-       rmon_update(mac, REG_RX_MULTICAST(port),
-                   &mac->stats.RxMulticastFramesOK);
-       rmon_update(mac, REG_RX_BROADCAST(port),
-                   &mac->stats.RxBroadcastFramesOK);
-       rmon_update(mac, REG_CRC(port), &mac->stats.RxFCSErrors);
-       rmon_update(mac, REG_RX_ALIGNMENT(port), &mac->stats.RxAlignErrors);
-       rmon_update(mac, REG_RX_OVERSIZE(port),
-                   &mac->stats.RxFrameTooLongErrors);
-       rmon_update(mac, REG_RX_PAUSE(port), &mac->stats.RxPauseFrames);
-       rmon_update(mac, REG_RX_JABBERS(port), &mac->stats.RxJabberErrors);
-       rmon_update(mac, REG_RX_FRAGMENTS(port), &mac->stats.RxRuntErrors);
-       rmon_update(mac, REG_RX_UNDERSIZE(port), &mac->stats.RxRuntErrors);
-       rmon_update(mac, REG_RX_SYMBOL_CARRIER(port),
-                   &mac->stats.RxSymbolErrors);
-       rmon_update(mac, REG_RX_SIZE_1519_TO_MAX(port),
-            &mac->stats.RxJumboFramesOK);
-
-       /* Tx stats (skip collision stats as we are full-duplex only) */
-       rmon_update(mac, REG_TX_OK_BYTES(port), &mac->stats.TxOctetsOK);
-       rmon_update(mac, REG_TX_UNICAST(port), &mac->stats.TxUnicastFramesOK);
-       rmon_update(mac, REG_TX_MULTICAST(port),
-                   &mac->stats.TxMulticastFramesOK);
-       rmon_update(mac, REG_TX_BROADCAST(port),
-                   &mac->stats.TxBroadcastFramesOK);
-       rmon_update(mac, REG_TX_PAUSE(port), &mac->stats.TxPauseFrames);
-       rmon_update(mac, REG_TX_UNDERRUN(port), &mac->stats.TxUnderrun);
-       rmon_update(mac, REG_TX_SIZE_1519_TO_MAX(port),
-            &mac->stats.TxJumboFramesOK);
 }
 
 /*
@@ -686,7 +690,8 @@ static struct cmac *vsc7326_mac_create(adapter_t *adapter, int index)
        int i;
 
        mac = kzalloc(sizeof(*mac) + sizeof(cmac_instance), GFP_KERNEL);
-       if (!mac) return NULL;
+       if (!mac)
+               return NULL;
 
        mac->ops = &vsc7326_ops;
        mac->instance = (cmac_instance *)(mac + 1);
index 491bcf7..479edbc 100644 (file)
 #define REG_HDX(pn)            CRA(0x1,pn,0x19)        /* Half-duplex config */
 
 /* Statistics */
+/* CRA(0x4,pn,reg) */
+/* reg below */
 /* pn = port number, 0-a, a = 10GbE */
-#define REG_RX_IN_BYTES(pn)    CRA(0x4,pn,0x00)        /* # Rx in octets */
-#define REG_RX_SYMBOL_CARRIER(pn) CRA(0x4,pn,0x01)     /* Frames w/ symbol errors */
-#define REG_RX_PAUSE(pn)       CRA(0x4,pn,0x02)        /* # pause frames received */
-#define REG_RX_UNSUP_OPCODE(pn)        CRA(0x4,pn,0x03)        /* # control frames with unsupported opcode */
-#define REG_RX_OK_BYTES(pn)    CRA(0x4,pn,0x04)        /* # octets in good frames */
-#define REG_RX_BAD_BYTES(pn)   CRA(0x4,pn,0x05)        /* # octets in bad frames */
-#define REG_RX_UNICAST(pn)     CRA(0x4,pn,0x06)        /* # good unicast frames */
-#define REG_RX_MULTICAST(pn)   CRA(0x4,pn,0x07)        /* # good multicast frames */
-#define REG_RX_BROADCAST(pn)   CRA(0x4,pn,0x08)        /* # good broadcast frames */
-#define REG_CRC(pn)            CRA(0x4,pn,0x09)        /* # frames w/ bad CRC only */
-#define REG_RX_ALIGNMENT(pn)   CRA(0x4,pn,0x0a)        /* # frames w/ alignment err */
-#define REG_RX_UNDERSIZE(pn)   CRA(0x4,pn,0x0b)        /* # frames undersize */
-#define REG_RX_FRAGMENTS(pn)   CRA(0x4,pn,0x0c)        /* # frames undersize w/ crc err */
-#define REG_RX_IN_RANGE_LENGTH_ERROR(pn) CRA(0x4,pn,0x0d)      /* # frames with length error */
-#define REG_RX_OUT_OF_RANGE_ERROR(pn) CRA(0x4,pn,0x0e) /* # frames with illegal length field */
-#define REG_RX_OVERSIZE(pn)    CRA(0x4,pn,0x0f)        /* # frames oversize */
-#define REG_RX_JABBERS(pn)     CRA(0x4,pn,0x10)        /* # frames oversize w/ crc err */
-#define REG_RX_SIZE_64(pn)     CRA(0x4,pn,0x11)        /* # frames 64 octets long */
-#define REG_RX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x12)     /* # frames 65-127 octets */
-#define REG_RX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x13)    /* # frames 128-255 */
-#define REG_RX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x14)    /* # frames 256-511 */
-#define REG_RX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x15)   /* # frames 512-1023 */
-#define REG_RX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x16)  /* # frames 1024-1518 */
-#define REG_RX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x17)   /* # frames 1519-max */
 
-#define REG_TX_OUT_BYTES(pn)   CRA(0x4,pn,0x18)        /* # octets tx */
-#define REG_TX_PAUSE(pn)       CRA(0x4,pn,0x19)        /* # pause frames sent */
-#define REG_TX_OK_BYTES(pn)    CRA(0x4,pn,0x1a)        /* # octets tx OK */
-#define REG_TX_UNICAST(pn)     CRA(0x4,pn,0x1b)        /* # frames unicast */
-#define REG_TX_MULTICAST(pn)   CRA(0x4,pn,0x1c)        /* # frames multicast */
-#define REG_TX_BROADCAST(pn)   CRA(0x4,pn,0x1d)        /* # frames broadcast */
-#define REG_TX_MULTIPLE_COLL(pn) CRA(0x4,pn,0x1e)      /* # frames tx after multiple collisions */
-#define REG_TX_LATE_COLL(pn)   CRA(0x4,pn,0x1f)        /* # late collisions detected */
-#define REG_TX_XCOLL(pn)       CRA(0x4,pn,0x20)        /* # frames lost, excessive collisions */
-#define REG_TX_DEFER(pn)       CRA(0x4,pn,0x21)        /* # frames deferred on first tx attempt */
-#define REG_TX_XDEFER(pn)      CRA(0x4,pn,0x22)        /* # frames excessively deferred */
-#define REG_TX_CSENSE(pn)      CRA(0x4,pn,0x23)        /* carrier sense errors at frame end */
-#define REG_TX_SIZE_64(pn)     CRA(0x4,pn,0x24)        /* # frames 64 octets long */
-#define REG_TX_SIZE_65_TO_127(pn) CRA(0x4,pn,0x25)     /* # frames 65-127 octets */
-#define REG_TX_SIZE_128_TO_255(pn) CRA(0x4,pn,0x26)    /* # frames 128-255 */
-#define REG_TX_SIZE_256_TO_511(pn) CRA(0x4,pn,0x27)    /* # frames 256-511 */
-#define REG_TX_SIZE_512_TO_1023(pn) CRA(0x4,pn,0x28)   /* # frames 512-1023 */
-#define REG_TX_SIZE_1024_TO_1518(pn) CRA(0x4,pn,0x29)  /* # frames 1024-1518 */
-#define REG_TX_SIZE_1519_TO_MAX(pn) CRA(0x4,pn,0x2a)   /* # frames 1519-max */
-#define REG_TX_SINGLE_COLL(pn) CRA(0x4,pn,0x2b)        /* # frames tx after single collision */
-#define REG_TX_BACKOFF2(pn)    CRA(0x4,pn,0x2c)        /* # frames tx ok after 2 backoffs/collisions */
-#define REG_TX_BACKOFF3(pn)    CRA(0x4,pn,0x2d)        /*   after 3 backoffs/collisions */
-#define REG_TX_BACKOFF4(pn)    CRA(0x4,pn,0x2e)        /*   after 4 */
-#define REG_TX_BACKOFF5(pn)    CRA(0x4,pn,0x2f)        /*   after 5 */
-#define REG_TX_BACKOFF6(pn)    CRA(0x4,pn,0x30)        /*   after 6 */
-#define REG_TX_BACKOFF7(pn)    CRA(0x4,pn,0x31)        /*   after 7 */
-#define REG_TX_BACKOFF8(pn)    CRA(0x4,pn,0x32)        /*   after 8 */
-#define REG_TX_BACKOFF9(pn)    CRA(0x4,pn,0x33)        /*   after 9 */
-#define REG_TX_BACKOFF10(pn)   CRA(0x4,pn,0x34)        /*   after 10 */
-#define REG_TX_BACKOFF11(pn)   CRA(0x4,pn,0x35)        /*   after 11 */
-#define REG_TX_BACKOFF12(pn)   CRA(0x4,pn,0x36)        /*   after 12 */
-#define REG_TX_BACKOFF13(pn)   CRA(0x4,pn,0x37)        /*   after 13 */
-#define REG_TX_BACKOFF14(pn)   CRA(0x4,pn,0x38)        /*   after 14 */
-#define REG_TX_BACKOFF15(pn)   CRA(0x4,pn,0x39)        /*   after 15 */
-#define REG_TX_UNDERRUN(pn)    CRA(0x4,pn,0x3a)        /* # frames dropped from underrun */
-#define REG_RX_XGMII_PROT_ERR  CRA(0x4,0xa,0x3b)       /* # protocol errors detected on XGMII interface */
-#define REG_RX_IPG_SHRINK(pn)  CRA(0x4,pn,0x3c)        /* # of IPG shrinks detected */
+enum {
+       RxInBytes               = 0x00, // # Rx in octets
+       RxSymbolCarrier         = 0x01, // Frames w/ symbol errors
+       RxPause                 = 0x02, // # pause frames received
+       RxUnsupOpcode           = 0x03, // # control frames with unsupported opcode
+       RxOkBytes               = 0x04, // # octets in good frames
+       RxBadBytes              = 0x05, // # octets in bad frames
+       RxUnicast               = 0x06, // # good unicast frames
+       RxMulticast             = 0x07, // # good multicast frames
+       RxBroadcast             = 0x08, // # good broadcast frames
+       Crc                     = 0x09, // # frames w/ bad CRC only
+       RxAlignment             = 0x0a, // # frames w/ alignment err
+       RxUndersize             = 0x0b, // # frames undersize
+       RxFragments             = 0x0c, // # frames undersize w/ crc err
+       RxInRangeLengthError    = 0x0d, // # frames with length error
+       RxOutOfRangeError       = 0x0e, // # frames with illegal length field
+       RxOversize              = 0x0f, // # frames oversize
+       RxJabbers               = 0x10, // # frames oversize w/ crc err
+       RxSize64                = 0x11, // # frames 64 octets long
+       RxSize65To127           = 0x12, // # frames 65-127 octets
+       RxSize128To255          = 0x13, // # frames 128-255
+       RxSize256To511          = 0x14, // # frames 256-511
+       RxSize512To1023         = 0x15, // # frames 512-1023
+       RxSize1024To1518        = 0x16, // # frames 1024-1518
+       RxSize1519ToMax         = 0x17, // # frames 1519-max
 
-#define REG_STAT_STICKY1G(pn)  CRA(0x4,pn,0x3e)        /* tri-speed sticky bits */
-#define REG_STAT_STICKY10G     CRA(0x4,0xa,0x3e)       /* 10GbE sticky bits */
-#define REG_STAT_INIT(pn)      CRA(0x4,pn,0x3f)        /* Clear all statistics */
+       TxOutBytes              = 0x18, // # octets tx
+       TxPause                 = 0x19, // # pause frames sent
+       TxOkBytes               = 0x1a, // # octets tx OK
+       TxUnicast               = 0x1b, // # frames unicast
+       TxMulticast             = 0x1c, // # frames multicast
+       TxBroadcast             = 0x1d, // # frames broadcast
+       TxMultipleColl          = 0x1e, // # frames tx after multiple collisions
+       TxLateColl              = 0x1f, // # late collisions detected
+       TxXcoll                 = 0x20, // # frames lost, excessive collisions
+       TxDefer                 = 0x21, // # frames deferred on first tx attempt
+       TxXdefer                = 0x22, // # frames excessively deferred
+       TxCsense                = 0x23, // carrier sense errors at frame end
+       TxSize64                = 0x24, // # frames 64 octets long
+       TxSize65To127           = 0x25, // # frames 65-127 octets
+       TxSize128To255          = 0x26, // # frames 128-255
+       TxSize256To511          = 0x27, // # frames 256-511
+       TxSize512To1023         = 0x28, // # frames 512-1023
+       TxSize1024To1518        = 0x29, // # frames 1024-1518
+       TxSize1519ToMax         = 0x2a, // # frames 1519-max
+       TxSingleColl            = 0x2b, // # frames tx after single collision
+       TxBackoff2              = 0x2c, // # frames tx ok after 2 backoffs/collisions
+       TxBackoff3              = 0x2d, //   after 3 backoffs/collisions
+       TxBackoff4              = 0x2e, //   after 4
+       TxBackoff5              = 0x2f, //   after 5
+       TxBackoff6              = 0x30, //   after 6
+       TxBackoff7              = 0x31, //   after 7
+       TxBackoff8              = 0x32, //   after 8
+       TxBackoff9              = 0x33, //   after 9
+       TxBackoff10             = 0x34, //   after 10
+       TxBackoff11             = 0x35, //   after 11
+       TxBackoff12             = 0x36, //   after 12
+       TxBackoff13             = 0x37, //   after 13
+       TxBackoff14             = 0x38, //   after 14
+       TxBackoff15             = 0x39, //   after 15
+       TxUnderrun              = 0x3a, // # frames dropped from underrun
+       // Hole. See REG_RX_XGMII_PROT_ERR below.
+       RxIpgShrink             = 0x3c, // # of IPG shrinks detected
+       // Duplicate. See REG_STAT_STICKY10G below.
+       StatSticky1G            = 0x3e, // tri-speed sticky bits
+       StatInit                = 0x3f  // Clear all statistics
+};
+
+#define REG_RX_XGMII_PROT_ERR  CRA(0x4,0xa,0x3b)               /* # protocol errors detected on XGMII interface */
+#define REG_STAT_STICKY10G     CRA(0x4,0xa,StatSticky1G)       /* 10GbE sticky bits */
+
+#define REG_RX_OK_BYTES(pn)    CRA(0x4,pn,RxOkBytes)
+#define REG_RX_BAD_BYTES(pn)   CRA(0x4,pn,RxBadBytes)
+#define REG_TX_OK_BYTES(pn)    CRA(0x4,pn,TxOkBytes)
 
 /* MII-Management Block registers */
 /* These are for MII-M interface 0, which is the bidirectional LVTTL one.  If
index c493e78..251d485 100644 (file)
@@ -54,7 +54,7 @@ enum {
 };
 
 #define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
-                          VSC_INTR_NEG_DONE)
+                          VSC_INTR_NEG_DONE)
 #define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
                   VSC_INTR_ENABLE)
 
@@ -94,19 +94,18 @@ static int vsc8244_intr_enable(struct cphy *cphy)
 {
        simple_mdio_write(cphy, VSC8244_INTR_ENABLE, INTR_MASK);
 
-    /* Enable interrupts through Elmer */
+       /* Enable interrupts through Elmer */
        if (t1_is_asic(cphy->adapter)) {
                u32 elmer;
 
                t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
                elmer |= ELMER0_GP_BIT1;
-               if (is_T2(cphy->adapter)) {
+               if (is_T2(cphy->adapter))
                    elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
-                }
                t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
        }
 
-    return 0;
+       return 0;
 }
 
 static int vsc8244_intr_disable(struct cphy *cphy)
@@ -118,19 +117,18 @@ static int vsc8244_intr_disable(struct cphy *cphy)
 
                t1_tpi_read(cphy->adapter, A_ELMER0_INT_ENABLE, &elmer);
                elmer &= ~ELMER0_GP_BIT1;
-               if (is_T2(cphy->adapter)) {
+               if (is_T2(cphy->adapter))
                    elmer &= ~(ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4);
-                }
                t1_tpi_write(cphy->adapter, A_ELMER0_INT_ENABLE, elmer);
        }
 
-    return 0;
+       return 0;
 }
 
 static int vsc8244_intr_clear(struct cphy *cphy)
 {
        u32 val;
-    u32 elmer;
+       u32 elmer;
 
        /* Clear PHY interrupts by reading the register. */
        simple_mdio_read(cphy, VSC8244_INTR_ENABLE, &val);
@@ -138,13 +136,12 @@ static int vsc8244_intr_clear(struct cphy *cphy)
        if (t1_is_asic(cphy->adapter)) {
                t1_tpi_read(cphy->adapter, A_ELMER0_INT_CAUSE, &elmer);
                elmer |= ELMER0_GP_BIT1;
-               if (is_T2(cphy->adapter)) {
+               if (is_T2(cphy->adapter))
                    elmer |= ELMER0_GP_BIT2|ELMER0_GP_BIT3|ELMER0_GP_BIT4;
-                }
                t1_tpi_write(cphy->adapter, A_ELMER0_INT_CAUSE, elmer);
        }
 
-    return 0;
+       return 0;
 }
 
 /*
@@ -179,13 +176,13 @@ static int vsc8244_set_speed_duplex(struct cphy *phy, int speed, int duplex)
 
 int t1_mdio_set_bits(struct cphy *phy, int mmd, int reg, unsigned int bits)
 {
-    int ret;
-    unsigned int val;
+       int ret;
+       unsigned int val;
 
-    ret = mdio_read(phy, mmd, reg, &val);
-    if (!ret)
-        ret = mdio_write(phy, mmd, reg, val | bits);
-    return ret;
+       ret = mdio_read(phy, mmd, reg, &val);
+       if (!ret)
+               ret = mdio_write(phy, mmd, reg, val | bits);
+       return ret;
 }
 
 static int vsc8244_autoneg_enable(struct cphy *cphy)
@@ -235,7 +232,7 @@ static int vsc8244_advertise(struct cphy *phy, unsigned int advertise_map)
 }
 
 static int vsc8244_get_link_status(struct cphy *cphy, int *link_ok,
-                                    int *speed, int *duplex, int *fc)
+                                  int *speed, int *duplex, int *fc)
 {
        unsigned int bmcr, status, lpa, adv;
        int err, sp = -1, dplx = -1, pause = 0;
@@ -343,11 +340,13 @@ static struct cphy_ops vsc8244_ops = {
        .get_link_status      = vsc8244_get_link_status
 };
 
-static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr, struct mdio_ops *mdio_ops)
+static struct cphy* vsc8244_phy_create(adapter_t *adapter, int phy_addr,
+                                      struct mdio_ops *mdio_ops)
 {
        struct cphy *cphy = kzalloc(sizeof(*cphy), GFP_KERNEL);
 
-       if (!cphy) return NULL;
+       if (!cphy)
+               return NULL;
 
        cphy_init(cphy, adapter, phy_addr, &vsc8244_ops, mdio_ops);
 
diff --git a/drivers/net/cxgb3/Makefile b/drivers/net/cxgb3/Makefile
new file mode 100644 (file)
index 0000000..3434679
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# Chelsio T3 driver
+#
+
+obj-$(CONFIG_CHELSIO_T3) += cxgb3.o
+
+cxgb3-objs := cxgb3_main.o ael1002.o vsc8211.o t3_hw.o mc5.o \
+             xgmac.o sge.o l2t.o cxgb3_offload.o
diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h
new file mode 100644 (file)
index 0000000..5c97a64
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/* This file should not be included directly.  Include common.h instead. */
+
+#ifndef __T3_ADAPTER_H__
+#define __T3_ADAPTER_H__
+
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/cache.h>
+#include <linux/mutex.h>
+#include "t3cdev.h"
+#include <asm/semaphore.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+typedef irqreturn_t(*intr_handler_t) (int, void *);
+
+struct vlan_group;
+
+struct port_info {
+       struct vlan_group *vlan_grp;
+       const struct port_type_info *port_type;
+       u8 port_id;
+       u8 rx_csum_offload;
+       u8 nqsets;
+       u8 first_qset;
+       struct cphy phy;
+       struct cmac mac;
+       struct link_config link_config;
+       struct net_device_stats netstats;
+       int activity;
+};
+
+enum {                         /* adapter flags */
+       FULL_INIT_DONE = (1 << 0),
+       USING_MSI = (1 << 1),
+       USING_MSIX = (1 << 2),
+       QUEUES_BOUND = (1 << 3),
+};
+
+struct rx_desc;
+struct rx_sw_desc;
+
+struct sge_fl {                        /* SGE per free-buffer list state */
+       unsigned int buf_size;  /* size of each Rx buffer */
+       unsigned int credits;   /* # of available Rx buffers */
+       unsigned int size;      /* capacity of free list */
+       unsigned int cidx;      /* consumer index */
+       unsigned int pidx;      /* producer index */
+       unsigned int gen;       /* free list generation */
+       struct rx_desc *desc;   /* address of HW Rx descriptor ring */
+       struct rx_sw_desc *sdesc;       /* address of SW Rx descriptor ring */
+       dma_addr_t phys_addr;   /* physical address of HW ring start */
+       unsigned int cntxt_id;  /* SGE context id for the free list */
+       unsigned long empty;    /* # of times queue ran out of buffers */
+};
+
+/*
+ * Bundle size for grouping offload RX packets for delivery to the stack.
+ * Don't make this too big as we do prefetch on each packet in a bundle.
+ */
+# define RX_BUNDLE_SIZE 8
+
+struct rsp_desc;
+
+struct sge_rspq {              /* state for an SGE response queue */
+       unsigned int credits;   /* # of pending response credits */
+       unsigned int size;      /* capacity of response queue */
+       unsigned int cidx;      /* consumer index */
+       unsigned int gen;       /* current generation bit */
+       unsigned int polling;   /* is the queue serviced through NAPI? */
+       unsigned int holdoff_tmr;       /* interrupt holdoff timer in 100ns */
+       unsigned int next_holdoff;      /* holdoff time for next interrupt */
+       struct rsp_desc *desc;  /* address of HW response ring */
+       dma_addr_t phys_addr;   /* physical address of the ring */
+       unsigned int cntxt_id;  /* SGE context id for the response q */
+       spinlock_t lock;        /* guards response processing */
+       struct sk_buff *rx_head;        /* offload packet receive queue head */
+       struct sk_buff *rx_tail;        /* offload packet receive queue tail */
+
+       unsigned long offload_pkts;
+       unsigned long offload_bundles;
+       unsigned long eth_pkts; /* # of ethernet packets */
+       unsigned long pure_rsps;        /* # of pure (non-data) responses */
+       unsigned long imm_data; /* responses with immediate data */
+       unsigned long rx_drops; /* # of packets dropped due to no mem */
+       unsigned long async_notif; /* # of asynchronous notification events */
+       unsigned long empty;    /* # of times queue ran out of credits */
+       unsigned long nomem;    /* # of responses deferred due to no mem */
+       unsigned long unhandled_irqs;   /* # of spurious intrs */
+};
+
+struct tx_desc;
+struct tx_sw_desc;
+
+struct sge_txq {               /* state for an SGE Tx queue */
+       unsigned long flags;    /* HW DMA fetch status */
+       unsigned int in_use;    /* # of in-use Tx descriptors */
+       unsigned int size;      /* # of descriptors */
+       unsigned int processed; /* total # of descs HW has processed */
+       unsigned int cleaned;   /* total # of descs SW has reclaimed */
+       unsigned int stop_thres;        /* SW TX queue suspend threshold */
+       unsigned int cidx;      /* consumer index */
+       unsigned int pidx;      /* producer index */
+       unsigned int gen;       /* current value of generation bit */
+       unsigned int unacked;   /* Tx descriptors used since last COMPL */
+       struct tx_desc *desc;   /* address of HW Tx descriptor ring */
+       struct tx_sw_desc *sdesc;       /* address of SW Tx descriptor ring */
+       spinlock_t lock;        /* guards enqueueing of new packets */
+       unsigned int token;     /* WR token */
+       dma_addr_t phys_addr;   /* physical address of the ring */
+       struct sk_buff_head sendq;      /* List of backpressured offload packets */
+       struct tasklet_struct qresume_tsk;      /* restarts the queue */
+       unsigned int cntxt_id;  /* SGE context id for the Tx q */
+       unsigned long stops;    /* # of times q has been stopped */
+       unsigned long restarts; /* # of queue restarts */
+};
+
+enum {                         /* per port SGE statistics */
+       SGE_PSTAT_TSO,          /* # of TSO requests */
+       SGE_PSTAT_RX_CSUM_GOOD, /* # of successful RX csum offloads */
+       SGE_PSTAT_TX_CSUM,      /* # of TX checksum offloads */
+       SGE_PSTAT_VLANEX,       /* # of VLAN tag extractions */
+       SGE_PSTAT_VLANINS,      /* # of VLAN tag insertions */
+
+       SGE_PSTAT_MAX           /* must be last */
+};
+
+struct sge_qset {              /* an SGE queue set */
+       struct sge_rspq rspq;
+       struct sge_fl fl[SGE_RXQ_PER_SET];
+       struct sge_txq txq[SGE_TXQ_PER_SET];
+       struct net_device *netdev;      /* associated net device */
+       unsigned long txq_stopped;      /* which Tx queues are stopped */
+       struct timer_list tx_reclaim_timer;     /* reclaims TX buffers */
+       unsigned long port_stats[SGE_PSTAT_MAX];
+} ____cacheline_aligned;
+
+struct sge {
+       struct sge_qset qs[SGE_QSETS];
+       spinlock_t reg_lock;    /* guards non-atomic SGE registers (eg context) */
+};
+
+struct adapter {
+       struct t3cdev tdev;
+       struct list_head adapter_list;
+       void __iomem *regs;
+       struct pci_dev *pdev;
+       unsigned long registered_device_map;
+       unsigned long open_device_map;
+       unsigned long flags;
+
+       const char *name;
+       int msg_enable;
+       unsigned int mmio_len;
+
+       struct adapter_params params;
+       unsigned int slow_intr_mask;
+       unsigned long irq_stats[IRQ_NUM_STATS];
+
+       struct {
+               unsigned short vec;
+               char desc[22];
+       } msix_info[SGE_QSETS + 1];
+
+       /* T3 modules */
+       struct sge sge;
+       struct mc7 pmrx;
+       struct mc7 pmtx;
+       struct mc7 cm;
+       struct mc5 mc5;
+
+       struct net_device *port[MAX_NPORTS];
+       unsigned int check_task_cnt;
+       struct delayed_work adap_check_task;
+       struct work_struct ext_intr_handler_task;
+
+       /*
+        * Dummy netdevices are needed when using multiple receive queues with
+        * NAPI as each netdevice can service only one queue.
+        */
+       struct net_device *dummy_netdev[SGE_QSETS - 1];
+
+       struct dentry *debugfs_root;
+
+       struct mutex mdio_lock;
+       spinlock_t stats_lock;
+       spinlock_t work_lock;
+};
+
+static inline u32 t3_read_reg(struct adapter *adapter, u32 reg_addr)
+{
+       u32 val = readl(adapter->regs + reg_addr);
+
+       CH_DBG(adapter, MMIO, "read register 0x%x value 0x%x\n", reg_addr, val);
+       return val;
+}
+
+static inline void t3_write_reg(struct adapter *adapter, u32 reg_addr, u32 val)
+{
+       CH_DBG(adapter, MMIO, "setting register 0x%x to 0x%x\n", reg_addr, val);
+       writel(val, adapter->regs + reg_addr);
+}
+
+static inline struct port_info *adap2pinfo(struct adapter *adap, int idx)
+{
+       return netdev_priv(adap->port[idx]);
+}
+
+/*
+ * We use the spare atalk_ptr to map a net device to its SGE queue set.
+ * This is a macro so it can be used as l-value.
+ */
+#define dev2qset(netdev) ((netdev)->atalk_ptr)
+
+#define OFFLOAD_DEVMAP_BIT 15
+
+#define tdev2adap(d) container_of(d, struct adapter, tdev)
+
+static inline int offload_running(struct adapter *adapter)
+{
+       return test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+}
+
+int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb);
+
+void t3_os_ext_intr_handler(struct adapter *adapter);
+void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status,
+                       int speed, int duplex, int fc);
+
+void t3_sge_start(struct adapter *adap);
+void t3_sge_stop(struct adapter *adap);
+void t3_free_sge_resources(struct adapter *adap);
+void t3_sge_err_intr_handler(struct adapter *adapter);
+intr_handler_t t3_intr_handler(struct adapter *adap, int polling);
+int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev);
+int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb);
+void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p);
+int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
+                     int irq_vec_idx, const struct qset_params *p,
+                     int ntxq, struct net_device *netdev);
+int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
+               unsigned char *data);
+irqreturn_t t3_sge_intr_msix(int irq, void *cookie);
+
+#endif                         /* __T3_ADAPTER_H__ */
diff --git a/drivers/net/cxgb3/ael1002.c b/drivers/net/cxgb3/ael1002.c
new file mode 100644 (file)
index 0000000..73a41e6
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+enum {
+       AEL100X_TX_DISABLE = 9,
+       AEL100X_TX_CONFIG1 = 0xc002,
+       AEL1002_PWR_DOWN_HI = 0xc011,
+       AEL1002_PWR_DOWN_LO = 0xc012,
+       AEL1002_XFI_EQL = 0xc015,
+       AEL1002_LB_EN = 0xc017,
+
+       LASI_CTRL = 0x9002,
+       LASI_STAT = 0x9005
+};
+
+static void ael100x_txon(struct cphy *phy)
+{
+       int tx_on_gpio = phy->addr == 0 ? F_GPIO7_OUT_VAL : F_GPIO2_OUT_VAL;
+
+       msleep(100);
+       t3_set_reg_field(phy->adapter, A_T3DBG_GPIO_EN, 0, tx_on_gpio);
+       msleep(30);
+}
+
+static int ael1002_power_down(struct cphy *phy, int enable)
+{
+       int err;
+
+       err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_DISABLE, !!enable);
+       if (!err)
+               err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
+                                         BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
+       return err;
+}
+
+static int ael1002_reset(struct cphy *phy, int wait)
+{
+       int err;
+
+       if ((err = ael1002_power_down(phy, 0)) ||
+           (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL100X_TX_CONFIG1, 1)) ||
+           (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_HI, 0)) ||
+           (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_PWR_DOWN_LO, 0)) ||
+           (err = mdio_write(phy, MDIO_DEV_PMA_PMD, AEL1002_XFI_EQL, 0x18)) ||
+           (err = t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, AEL1002_LB_EN,
+                                      0, 1 << 5)))
+               return err;
+       return 0;
+}
+
+static int ael1002_intr_noop(struct cphy *phy)
+{
+       return 0;
+}
+
+static int ael100x_get_link_status(struct cphy *phy, int *link_ok,
+                                  int *speed, int *duplex, int *fc)
+{
+       if (link_ok) {
+               unsigned int status;
+               int err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &status);
+
+               /*
+                * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
+                * once more to get the current link state.
+                */
+               if (!err && !(status & BMSR_LSTATUS))
+                       err = mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR,
+                                       &status);
+               if (err)
+                       return err;
+               *link_ok = !!(status & BMSR_LSTATUS);
+       }
+       if (speed)
+               *speed = SPEED_10000;
+       if (duplex)
+               *duplex = DUPLEX_FULL;
+       return 0;
+}
+
+static struct cphy_ops ael1002_ops = {
+       .reset = ael1002_reset,
+       .intr_enable = ael1002_intr_noop,
+       .intr_disable = ael1002_intr_noop,
+       .intr_clear = ael1002_intr_noop,
+       .intr_handler = ael1002_intr_noop,
+       .get_link_status = ael100x_get_link_status,
+       .power_down = ael1002_power_down,
+};
+
+void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
+                        int phy_addr, const struct mdio_ops *mdio_ops)
+{
+       cphy_init(phy, adapter, phy_addr, &ael1002_ops, mdio_ops);
+       ael100x_txon(phy);
+}
+
+static int ael1006_reset(struct cphy *phy, int wait)
+{
+       return t3_phy_reset(phy, MDIO_DEV_PMA_PMD, wait);
+}
+
+static int ael1006_intr_enable(struct cphy *phy)
+{
+       return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
+}
+
+static int ael1006_intr_disable(struct cphy *phy)
+{
+       return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
+}
+
+static int ael1006_intr_clear(struct cphy *phy)
+{
+       u32 val;
+
+       return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
+}
+
+static int ael1006_intr_handler(struct cphy *phy)
+{
+       unsigned int status;
+       int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
+
+       if (err)
+               return err;
+       return (status & 1) ? cphy_cause_link_change : 0;
+}
+
+static int ael1006_power_down(struct cphy *phy, int enable)
+{
+       return t3_mdio_change_bits(phy, MDIO_DEV_PMA_PMD, MII_BMCR,
+                                  BMCR_PDOWN, enable ? BMCR_PDOWN : 0);
+}
+
+static struct cphy_ops ael1006_ops = {
+       .reset = ael1006_reset,
+       .intr_enable = ael1006_intr_enable,
+       .intr_disable = ael1006_intr_disable,
+       .intr_clear = ael1006_intr_clear,
+       .intr_handler = ael1006_intr_handler,
+       .get_link_status = ael100x_get_link_status,
+       .power_down = ael1006_power_down,
+};
+
+void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
+                        int phy_addr, const struct mdio_ops *mdio_ops)
+{
+       cphy_init(phy, adapter, phy_addr, &ael1006_ops, mdio_ops);
+       ael100x_txon(phy);
+}
+
+static struct cphy_ops qt2045_ops = {
+       .reset = ael1006_reset,
+       .intr_enable = ael1006_intr_enable,
+       .intr_disable = ael1006_intr_disable,
+       .intr_clear = ael1006_intr_clear,
+       .intr_handler = ael1006_intr_handler,
+       .get_link_status = ael100x_get_link_status,
+       .power_down = ael1006_power_down,
+};
+
+void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter,
+                       int phy_addr, const struct mdio_ops *mdio_ops)
+{
+       unsigned int stat;
+
+       cphy_init(phy, adapter, phy_addr, &qt2045_ops, mdio_ops);
+
+       /*
+        * Some cards where the PHY is supposed to be at address 0 actually
+        * have it at 1.
+        */
+       if (!phy_addr && !mdio_read(phy, MDIO_DEV_PMA_PMD, MII_BMSR, &stat) &&
+           stat == 0xffff)
+               phy->addr = 1;
+}
+
+static int xaui_direct_reset(struct cphy *phy, int wait)
+{
+       return 0;
+}
+
+static int xaui_direct_get_link_status(struct cphy *phy, int *link_ok,
+                                      int *speed, int *duplex, int *fc)
+{
+       if (link_ok) {
+               unsigned int status;
+
+               status = t3_read_reg(phy->adapter,
+                                    XGM_REG(A_XGM_SERDES_STAT0, phy->addr));
+               *link_ok = !(status & F_LOWSIG0);
+       }
+       if (speed)
+               *speed = SPEED_10000;
+       if (duplex)
+               *duplex = DUPLEX_FULL;
+       return 0;
+}
+
+static int xaui_direct_power_down(struct cphy *phy, int enable)
+{
+       return 0;
+}
+
+static struct cphy_ops xaui_direct_ops = {
+       .reset = xaui_direct_reset,
+       .intr_enable = ael1002_intr_noop,
+       .intr_disable = ael1002_intr_noop,
+       .intr_clear = ael1002_intr_noop,
+       .intr_handler = ael1002_intr_noop,
+       .get_link_status = xaui_direct_get_link_status,
+       .power_down = xaui_direct_power_down,
+};
+
+void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
+                            int phy_addr, const struct mdio_ops *mdio_ops)
+{
+       cphy_init(phy, adapter, 1, &xaui_direct_ops, mdio_ops);
+}
diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h
new file mode 100644 (file)
index 0000000..e23deeb
--- /dev/null
@@ -0,0 +1,729 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __CHELSIO_COMMON_H
+#define __CHELSIO_COMMON_H
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include "version.h"
+
+#define CH_ERR(adap, fmt, ...)   dev_err(&adap->pdev->dev, fmt, ## __VA_ARGS__)
+#define CH_WARN(adap, fmt, ...)  dev_warn(&adap->pdev->dev, fmt, ## __VA_ARGS__)
+#define CH_ALERT(adap, fmt, ...) \
+       dev_printk(KERN_ALERT, &adap->pdev->dev, fmt, ## __VA_ARGS__)
+
+/*
+ * More powerful macro that selectively prints messages based on msg_enable.
+ * For info and debugging messages.
+ */
+#define CH_MSG(adapter, level, category, fmt, ...) do { \
+       if ((adapter)->msg_enable & NETIF_MSG_##category) \
+               dev_printk(KERN_##level, &adapter->pdev->dev, fmt, \
+                          ## __VA_ARGS__); \
+} while (0)
+
+#ifdef DEBUG
+# define CH_DBG(adapter, category, fmt, ...) \
+       CH_MSG(adapter, DEBUG, category, fmt, ## __VA_ARGS__)
+#else
+# define CH_DBG(adapter, category, fmt, ...)
+#endif
+
+/* Additional NETIF_MSG_* categories */
+#define NETIF_MSG_MMIO 0x8000000
+
+struct t3_rx_mode {
+       struct net_device *dev;
+       struct dev_mc_list *mclist;
+       unsigned int idx;
+};
+
+static inline void init_rx_mode(struct t3_rx_mode *p, struct net_device *dev,
+                               struct dev_mc_list *mclist)
+{
+       p->dev = dev;
+       p->mclist = mclist;
+       p->idx = 0;
+}
+
+static inline u8 *t3_get_next_mcaddr(struct t3_rx_mode *rm)
+{
+       u8 *addr = NULL;
+
+       if (rm->mclist && rm->idx < rm->dev->mc_count) {
+               addr = rm->mclist->dmi_addr;
+               rm->mclist = rm->mclist->next;
+               rm->idx++;
+       }
+       return addr;
+}
+
+enum {
+       MAX_NPORTS = 2,         /* max # of ports */
+       MAX_FRAME_SIZE = 10240, /* max MAC frame size, including header + FCS */
+       EEPROMSIZE = 8192,      /* Serial EEPROM size */
+       RSS_TABLE_SIZE = 64,    /* size of RSS lookup and mapping tables */
+       TCB_SIZE = 128,         /* TCB size */
+       NMTUS = 16,             /* size of MTU table */
+       NCCTRL_WIN = 32,        /* # of congestion control windows */
+};
+
+#define MAX_RX_COALESCING_LEN 16224U
+
+enum {
+       PAUSE_RX = 1 << 0,
+       PAUSE_TX = 1 << 1,
+       PAUSE_AUTONEG = 1 << 2
+};
+
+enum {
+       SUPPORTED_OFFLOAD = 1 << 24,
+       SUPPORTED_IRQ = 1 << 25
+};
+
+enum {                         /* adapter interrupt-maintained statistics */
+       STAT_ULP_CH0_PBL_OOB,
+       STAT_ULP_CH1_PBL_OOB,
+       STAT_PCI_CORR_ECC,
+
+       IRQ_NUM_STATS           /* keep last */
+};
+
+enum {
+       SGE_QSETS = 8,          /* # of SGE Tx/Rx/RspQ sets */
+       SGE_RXQ_PER_SET = 2,    /* # of Rx queues per set */
+       SGE_TXQ_PER_SET = 3     /* # of Tx queues per set */
+};
+
+enum sge_context_type {                /* SGE egress context types */
+       SGE_CNTXT_RDMA = 0,
+       SGE_CNTXT_ETH = 2,
+       SGE_CNTXT_OFLD = 4,
+       SGE_CNTXT_CTRL = 5
+};
+
+enum {
+       AN_PKT_SIZE = 32,       /* async notification packet size */
+       IMMED_PKT_SIZE = 48     /* packet size for immediate data */
+};
+
+struct sg_ent {                        /* SGE scatter/gather entry */
+       u32 len[2];
+       u64 addr[2];
+};
+
+#ifndef SGE_NUM_GENBITS
+/* Must be 1 or 2 */
+# define SGE_NUM_GENBITS 2
+#endif
+
+#define TX_DESC_FLITS 16U
+#define WR_FLITS (TX_DESC_FLITS + 1 - SGE_NUM_GENBITS)
+
+struct cphy;
+struct adapter;
+
+struct mdio_ops {
+       int (*read)(struct adapter *adapter, int phy_addr, int mmd_addr,
+                   int reg_addr, unsigned int *val);
+       int (*write)(struct adapter *adapter, int phy_addr, int mmd_addr,
+                    int reg_addr, unsigned int val);
+};
+
+struct adapter_info {
+       unsigned char nports;   /* # of ports */
+       unsigned char phy_base_addr;    /* MDIO PHY base address */
+       unsigned char mdien;
+       unsigned char mdiinv;
+       unsigned int gpio_out;  /* GPIO output settings */
+       unsigned int gpio_intr; /* GPIO IRQ enable mask */
+       unsigned long caps;     /* adapter capabilities */
+       const struct mdio_ops *mdio_ops;        /* MDIO operations */
+       const char *desc;       /* product description */
+};
+
+struct port_type_info {
+       void (*phy_prep)(struct cphy *phy, struct adapter *adapter,
+                        int phy_addr, const struct mdio_ops *ops);
+       unsigned int caps;
+       const char *desc;
+};
+
+struct mc5_stats {
+       unsigned long parity_err;
+       unsigned long active_rgn_full;
+       unsigned long nfa_srch_err;
+       unsigned long unknown_cmd;
+       unsigned long reqq_parity_err;
+       unsigned long dispq_parity_err;
+       unsigned long del_act_empty;
+};
+
+struct mc7_stats {
+       unsigned long corr_err;
+       unsigned long uncorr_err;
+       unsigned long parity_err;
+       unsigned long addr_err;
+};
+
+struct mac_stats {
+       u64 tx_octets;          /* total # of octets in good frames */
+       u64 tx_octets_bad;      /* total # of octets in error frames */
+       u64 tx_frames;          /* all good frames */
+       u64 tx_mcast_frames;    /* good multicast frames */
+       u64 tx_bcast_frames;    /* good broadcast frames */
+       u64 tx_pause;           /* # of transmitted pause frames */
+       u64 tx_deferred;        /* frames with deferred transmissions */
+       u64 tx_late_collisions; /* # of late collisions */
+       u64 tx_total_collisions;        /* # of total collisions */
+       u64 tx_excess_collisions;       /* frame errors from excessive collissions */
+       u64 tx_underrun;        /* # of Tx FIFO underruns */
+       u64 tx_len_errs;        /* # of Tx length errors */
+       u64 tx_mac_internal_errs;       /* # of internal MAC errors on Tx */
+       u64 tx_excess_deferral; /* # of frames with excessive deferral */
+       u64 tx_fcs_errs;        /* # of frames with bad FCS */
+
+       u64 tx_frames_64;       /* # of Tx frames in a particular range */
+       u64 tx_frames_65_127;
+       u64 tx_frames_128_255;
+       u64 tx_frames_256_511;
+       u64 tx_frames_512_1023;
+       u64 tx_frames_1024_1518;
+       u64 tx_frames_1519_max;
+
+       u64 rx_octets;          /* total # of octets in good frames */
+       u64 rx_octets_bad;      /* total # of octets in error frames */
+       u64 rx_frames;          /* all good frames */
+       u64 rx_mcast_frames;    /* good multicast frames */
+       u64 rx_bcast_frames;    /* good broadcast frames */
+       u64 rx_pause;           /* # of received pause frames */
+       u64 rx_fcs_errs;        /* # of received frames with bad FCS */
+       u64 rx_align_errs;      /* alignment errors */
+       u64 rx_symbol_errs;     /* symbol errors */
+       u64 rx_data_errs;       /* data errors */
+       u64 rx_sequence_errs;   /* sequence errors */
+       u64 rx_runt;            /* # of runt frames */
+       u64 rx_jabber;          /* # of jabber frames */
+       u64 rx_short;           /* # of short frames */
+       u64 rx_too_long;        /* # of oversized frames */
+       u64 rx_mac_internal_errs;       /* # of internal MAC errors on Rx */
+
+       u64 rx_frames_64;       /* # of Rx frames in a particular range */
+       u64 rx_frames_65_127;
+       u64 rx_frames_128_255;
+       u64 rx_frames_256_511;
+       u64 rx_frames_512_1023;
+       u64 rx_frames_1024_1518;
+       u64 rx_frames_1519_max;
+
+       u64 rx_cong_drops;      /* # of Rx drops due to SGE congestion */
+
+       unsigned long tx_fifo_parity_err;
+       unsigned long rx_fifo_parity_err;
+       unsigned long tx_fifo_urun;
+       unsigned long rx_fifo_ovfl;
+       unsigned long serdes_signal_loss;
+       unsigned long xaui_pcs_ctc_err;
+       unsigned long xaui_pcs_align_change;
+};
+
+struct tp_mib_stats {
+       u32 ipInReceive_hi;
+       u32 ipInReceive_lo;
+       u32 ipInHdrErrors_hi;
+       u32 ipInHdrErrors_lo;
+       u32 ipInAddrErrors_hi;
+       u32 ipInAddrErrors_lo;
+       u32 ipInUnknownProtos_hi;
+       u32 ipInUnknownProtos_lo;
+       u32 ipInDiscards_hi;
+       u32 ipInDiscards_lo;
+       u32 ipInDelivers_hi;
+       u32 ipInDelivers_lo;
+       u32 ipOutRequests_hi;
+       u32 ipOutRequests_lo;
+       u32 ipOutDiscards_hi;
+       u32 ipOutDiscards_lo;
+       u32 ipOutNoRoutes_hi;
+       u32 ipOutNoRoutes_lo;
+       u32 ipReasmTimeout;
+       u32 ipReasmReqds;
+       u32 ipReasmOKs;
+       u32 ipReasmFails;
+
+       u32 reserved[8];
+
+       u32 tcpActiveOpens;
+       u32 tcpPassiveOpens;
+       u32 tcpAttemptFails;
+       u32 tcpEstabResets;
+       u32 tcpOutRsts;
+       u32 tcpCurrEstab;
+       u32 tcpInSegs_hi;
+       u32 tcpInSegs_lo;
+       u32 tcpOutSegs_hi;
+       u32 tcpOutSegs_lo;
+       u32 tcpRetransSeg_hi;
+       u32 tcpRetransSeg_lo;
+       u32 tcpInErrs_hi;
+       u32 tcpInErrs_lo;
+       u32 tcpRtoMin;
+       u32 tcpRtoMax;
+};
+
+struct tp_params {
+       unsigned int nchan;     /* # of channels */
+       unsigned int pmrx_size; /* total PMRX capacity */
+       unsigned int pmtx_size; /* total PMTX capacity */
+       unsigned int cm_size;   /* total CM capacity */
+       unsigned int chan_rx_size;      /* per channel Rx size */
+       unsigned int chan_tx_size;      /* per channel Tx size */
+       unsigned int rx_pg_size;        /* Rx page size */
+       unsigned int tx_pg_size;        /* Tx page size */
+       unsigned int rx_num_pgs;        /* # of Rx pages */
+       unsigned int tx_num_pgs;        /* # of Tx pages */
+       unsigned int ntimer_qs; /* # of timer queues */
+};
+
+struct qset_params {           /* SGE queue set parameters */
+       unsigned int polling;   /* polling/interrupt service for rspq */
+       unsigned int coalesce_usecs;    /* irq coalescing timer */
+       unsigned int rspq_size; /* # of entries in response queue */
+       unsigned int fl_size;   /* # of entries in regular free list */
+       unsigned int jumbo_size;        /* # of entries in jumbo free list */
+       unsigned int txq_size[SGE_TXQ_PER_SET]; /* Tx queue sizes */
+       unsigned int cong_thres;        /* FL congestion threshold */
+};
+
+struct sge_params {
+       unsigned int max_pkt_size;      /* max offload pkt size */
+       struct qset_params qset[SGE_QSETS];
+};
+
+struct mc5_params {
+       unsigned int mode;      /* selects MC5 width */
+       unsigned int nservers;  /* size of server region */
+       unsigned int nfilters;  /* size of filter region */
+       unsigned int nroutes;   /* size of routing region */
+};
+
+/* Default MC5 region sizes */
+enum {
+       DEFAULT_NSERVERS = 512,
+       DEFAULT_NFILTERS = 128
+};
+
+/* MC5 modes, these must be non-0 */
+enum {
+       MC5_MODE_144_BIT = 1,
+       MC5_MODE_72_BIT = 2
+};
+
+struct vpd_params {
+       unsigned int cclk;
+       unsigned int mclk;
+       unsigned int uclk;
+       unsigned int mdc;
+       unsigned int mem_timing;
+       u8 eth_base[6];
+       u8 port_type[MAX_NPORTS];
+       unsigned short xauicfg[2];
+};
+
+struct pci_params {
+       unsigned int vpd_cap_addr;
+       unsigned int pcie_cap_addr;
+       unsigned short speed;
+       unsigned char width;
+       unsigned char variant;
+};
+
+enum {
+       PCI_VARIANT_PCI,
+       PCI_VARIANT_PCIX_MODE1_PARITY,
+       PCI_VARIANT_PCIX_MODE1_ECC,
+       PCI_VARIANT_PCIX_266_MODE2,
+       PCI_VARIANT_PCIE
+};
+
+struct adapter_params {
+       struct sge_params sge;
+       struct mc5_params mc5;
+       struct tp_params tp;
+       struct vpd_params vpd;
+       struct pci_params pci;
+
+       const struct adapter_info *info;
+
+       unsigned short mtus[NMTUS];
+       unsigned short a_wnd[NCCTRL_WIN];
+       unsigned short b_wnd[NCCTRL_WIN];
+
+       unsigned int nports;    /* # of ethernet ports */
+       unsigned int stats_update_period;       /* MAC stats accumulation period */
+       unsigned int linkpoll_period;   /* link poll period in 0.1s */
+       unsigned int rev;       /* chip revision */
+};
+
+struct trace_params {
+       u32 sip;
+       u32 sip_mask;
+       u32 dip;
+       u32 dip_mask;
+       u16 sport;
+       u16 sport_mask;
+       u16 dport;
+       u16 dport_mask;
+       u32 vlan:12;
+       u32 vlan_mask:12;
+       u32 intf:4;
+       u32 intf_mask:4;
+       u8 proto;
+       u8 proto_mask;
+};
+
+struct link_config {
+       unsigned int supported; /* link capabilities */
+       unsigned int advertising;       /* advertised capabilities */
+       unsigned short requested_speed; /* speed user has requested */
+       unsigned short speed;   /* actual link speed */
+       unsigned char requested_duplex; /* duplex user has requested */
+       unsigned char duplex;   /* actual link duplex */
+       unsigned char requested_fc;     /* flow control user has requested */
+       unsigned char fc;       /* actual link flow control */
+       unsigned char autoneg;  /* autonegotiating? */
+       unsigned int link_ok;   /* link up? */
+};
+
+#define SPEED_INVALID   0xffff
+#define DUPLEX_INVALID  0xff
+
+struct mc5 {
+       struct adapter *adapter;
+       unsigned int tcam_size;
+       unsigned char part_type;
+       unsigned char parity_enabled;
+       unsigned char mode;
+       struct mc5_stats stats;
+};
+
+static inline unsigned int t3_mc5_size(const struct mc5 *p)
+{
+       return p->tcam_size;
+}
+
+struct mc7 {
+       struct adapter *adapter;        /* backpointer to adapter */
+       unsigned int size;      /* memory size in bytes */
+       unsigned int width;     /* MC7 interface width */
+       unsigned int offset;    /* register address offset for MC7 instance */
+       const char *name;       /* name of MC7 instance */
+       struct mc7_stats stats; /* MC7 statistics */
+};
+
+static inline unsigned int t3_mc7_size(const struct mc7 *p)
+{
+       return p->size;
+}
+
+struct cmac {
+       struct adapter *adapter;
+       unsigned int offset;
+       unsigned int nucast;    /* # of address filters for unicast MACs */
+       struct mac_stats stats;
+};
+
+enum {
+       MAC_DIRECTION_RX = 1,
+       MAC_DIRECTION_TX = 2,
+       MAC_RXFIFO_SIZE = 32768
+};
+
+/* IEEE 802.3ae specified MDIO devices */
+enum {
+       MDIO_DEV_PMA_PMD = 1,
+       MDIO_DEV_WIS = 2,
+       MDIO_DEV_PCS = 3,
+       MDIO_DEV_XGXS = 4
+};
+
+/* PHY loopback direction */
+enum {
+       PHY_LOOPBACK_TX = 1,
+       PHY_LOOPBACK_RX = 2
+};
+
+/* PHY interrupt types */
+enum {
+       cphy_cause_link_change = 1,
+       cphy_cause_fifo_error = 2
+};
+
+/* PHY operations */
+struct cphy_ops {
+       void (*destroy)(struct cphy *phy);
+       int (*reset)(struct cphy *phy, int wait);
+
+       int (*intr_enable)(struct cphy *phy);
+       int (*intr_disable)(struct cphy *phy);
+       int (*intr_clear)(struct cphy *phy);
+       int (*intr_handler)(struct cphy *phy);
+
+       int (*autoneg_enable)(struct cphy *phy);
+       int (*autoneg_restart)(struct cphy *phy);
+
+       int (*advertise)(struct cphy *phy, unsigned int advertise_map);
+       int (*set_loopback)(struct cphy *phy, int mmd, int dir, int enable);
+       int (*set_speed_duplex)(struct cphy *phy, int speed, int duplex);
+       int (*get_link_status)(struct cphy *phy, int *link_ok, int *speed,
+                              int *duplex, int *fc);
+       int (*power_down)(struct cphy *phy, int enable);
+};
+
+/* A PHY instance */
+struct cphy {
+       int addr;               /* PHY address */
+       struct adapter *adapter;        /* associated adapter */
+       unsigned long fifo_errors;      /* FIFO over/under-flows */
+       const struct cphy_ops *ops;     /* PHY operations */
+       int (*mdio_read)(struct adapter *adapter, int phy_addr, int mmd_addr,
+                        int reg_addr, unsigned int *val);
+       int (*mdio_write)(struct adapter *adapter, int phy_addr, int mmd_addr,
+                         int reg_addr, unsigned int val);
+};
+
+/* Convenience MDIO read/write wrappers */
+static inline int mdio_read(struct cphy *phy, int mmd, int reg,
+                           unsigned int *valp)
+{
+       return phy->mdio_read(phy->adapter, phy->addr, mmd, reg, valp);
+}
+
+static inline int mdio_write(struct cphy *phy, int mmd, int reg,
+                            unsigned int val)
+{
+       return phy->mdio_write(phy->adapter, phy->addr, mmd, reg, val);
+}
+
+/* Convenience initializer */
+static inline void cphy_init(struct cphy *phy, struct adapter *adapter,
+                            int phy_addr, struct cphy_ops *phy_ops,
+                            const struct mdio_ops *mdio_ops)
+{
+       phy->adapter = adapter;
+       phy->addr = phy_addr;
+       phy->ops = phy_ops;
+       if (mdio_ops) {
+               phy->mdio_read = mdio_ops->read;
+               phy->mdio_write = mdio_ops->write;
+       }
+}
+
+/* Accumulate MAC statistics every 180 seconds.  For 1G we multiply by 10. */
+#define MAC_STATS_ACCUM_SECS 180
+
+#define XGM_REG(reg_addr, idx) \
+       ((reg_addr) + (idx) * (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR))
+
+struct addr_val_pair {
+       unsigned int reg_addr;
+       unsigned int val;
+};
+
+#include "adapter.h"
+
+#ifndef PCI_VENDOR_ID_CHELSIO
+# define PCI_VENDOR_ID_CHELSIO 0x1425
+#endif
+
+#define for_each_port(adapter, iter) \
+       for (iter = 0; iter < (adapter)->params.nports; ++iter)
+
+#define adapter_info(adap) ((adap)->params.info)
+
+static inline int uses_xaui(const struct adapter *adap)
+{
+       return adapter_info(adap)->caps & SUPPORTED_AUI;
+}
+
+static inline int is_10G(const struct adapter *adap)
+{
+       return adapter_info(adap)->caps & SUPPORTED_10000baseT_Full;
+}
+
+static inline int is_offload(const struct adapter *adap)
+{
+       return adapter_info(adap)->caps & SUPPORTED_OFFLOAD;
+}
+
+static inline unsigned int core_ticks_per_usec(const struct adapter *adap)
+{
+       return adap->params.vpd.cclk / 1000;
+}
+
+static inline unsigned int is_pcie(const struct adapter *adap)
+{
+       return adap->params.pci.variant == PCI_VARIANT_PCIE;
+}
+
+void t3_set_reg_field(struct adapter *adap, unsigned int addr, u32 mask,
+                     u32 val);
+void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p,
+                  int n, unsigned int offset);
+int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
+                       int polarity, int attempts, int delay, u32 *valp);
+static inline int t3_wait_op_done(struct adapter *adapter, int reg, u32 mask,
+                                 int polarity, int attempts, int delay)
+{
+       return t3_wait_op_done_val(adapter, reg, mask, polarity, attempts,
+                                  delay, NULL);
+}
+int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
+                       unsigned int set);
+int t3_phy_reset(struct cphy *phy, int mmd, int wait);
+int t3_phy_advertise(struct cphy *phy, unsigned int advert);
+int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex);
+
+void t3_intr_enable(struct adapter *adapter);
+void t3_intr_disable(struct adapter *adapter);
+void t3_intr_clear(struct adapter *adapter);
+void t3_port_intr_enable(struct adapter *adapter, int idx);
+void t3_port_intr_disable(struct adapter *adapter, int idx);
+void t3_port_intr_clear(struct adapter *adapter, int idx);
+int t3_slow_intr_handler(struct adapter *adapter);
+int t3_phy_intr_handler(struct adapter *adapter);
+
+void t3_link_changed(struct adapter *adapter, int port_id);
+int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
+const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
+int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data);
+int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data);
+int t3_seeprom_wp(struct adapter *adapter, int enable);
+int t3_read_flash(struct adapter *adapter, unsigned int addr,
+                 unsigned int nwords, u32 *data, int byte_oriented);
+int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size);
+int t3_get_fw_version(struct adapter *adapter, u32 *vers);
+int t3_check_fw_version(struct adapter *adapter);
+int t3_init_hw(struct adapter *adapter, u32 fw_params);
+void mac_prep(struct cmac *mac, struct adapter *adapter, int index);
+void early_hw_init(struct adapter *adapter, const struct adapter_info *ai);
+int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
+                   int reset);
+void t3_led_ready(struct adapter *adapter);
+void t3_fatal_err(struct adapter *adapter);
+void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on);
+void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
+                  const u8 * cpus, const u16 *rspq);
+int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map);
+int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask);
+int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
+                       unsigned int n, unsigned int *valp);
+int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
+                  u64 *buf);
+
+int t3_mac_reset(struct cmac *mac);
+void t3b_pcs_reset(struct cmac *mac);
+int t3_mac_enable(struct cmac *mac, int which);
+int t3_mac_disable(struct cmac *mac, int which);
+int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu);
+int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm);
+int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6]);
+int t3_mac_set_num_ucast(struct cmac *mac, int n);
+const struct mac_stats *t3_mac_update_stats(struct cmac *mac);
+int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc);
+
+void t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode);
+int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
+               unsigned int nroutes);
+void t3_mc5_intr_handler(struct mc5 *mc5);
+int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start, unsigned int n,
+                     u32 *buf);
+
+int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh);
+void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size);
+void t3_tp_set_offload_mode(struct adapter *adap, int enable);
+void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps);
+void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
+                 unsigned short alpha[NCCTRL_WIN],
+                 unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap);
+void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS]);
+void t3_get_cong_cntl_tab(struct adapter *adap,
+                         unsigned short incr[NMTUS][NCCTRL_WIN]);
+void t3_config_trace_filter(struct adapter *adapter,
+                           const struct trace_params *tp, int filter_index,
+                           int invert, int enable);
+int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched);
+
+void t3_sge_prep(struct adapter *adap, struct sge_params *p);
+void t3_sge_init(struct adapter *adap, struct sge_params *p);
+int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable,
+                      enum sge_context_type type, int respq, u64 base_addr,
+                      unsigned int size, unsigned int token, int gen,
+                      unsigned int cidx);
+int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id,
+                       int gts_enable, u64 base_addr, unsigned int size,
+                       unsigned int esize, unsigned int cong_thres, int gen,
+                       unsigned int cidx);
+int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id,
+                        int irq_vec_idx, u64 base_addr, unsigned int size,
+                        unsigned int fl_thres, int gen, unsigned int cidx);
+int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
+                       unsigned int size, int rspq, int ovfl_mode,
+                       unsigned int credits, unsigned int credit_thres);
+int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable);
+int t3_sge_disable_fl(struct adapter *adapter, unsigned int id);
+int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id);
+int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id);
+int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4]);
+int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
+                     unsigned int credits);
+
+void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
+                        int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_ael1002_phy_prep(struct cphy *phy, struct adapter *adapter,
+                        int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_ael1006_phy_prep(struct cphy *phy, struct adapter *adapter,
+                        int phy_addr, const struct mdio_ops *mdio_ops);
+void t3_qt2045_phy_prep(struct cphy *phy, struct adapter *adapter, int phy_addr,
+                       const struct mdio_ops *mdio_ops);
+void t3_xaui_direct_phy_prep(struct cphy *phy, struct adapter *adapter,
+                            int phy_addr, const struct mdio_ops *mdio_ops);
+#endif                         /* __CHELSIO_COMMON_H */
diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h
new file mode 100644 (file)
index 0000000..2095dda
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CXGB3_OFFLOAD_CTL_DEFS_H
+#define _CXGB3_OFFLOAD_CTL_DEFS_H
+
+enum {
+       GET_MAX_OUTSTANDING_WR,
+       GET_TX_MAX_CHUNK,
+       GET_TID_RANGE,
+       GET_STID_RANGE,
+       GET_RTBL_RANGE,
+       GET_L2T_CAPACITY,
+       GET_MTUS,
+       GET_WR_LEN,
+       GET_IFF_FROM_MAC,
+       GET_DDP_PARAMS,
+       GET_PORTS,
+
+       ULP_ISCSI_GET_PARAMS,
+       ULP_ISCSI_SET_PARAMS,
+
+       RDMA_GET_PARAMS,
+       RDMA_CQ_OP,
+       RDMA_CQ_SETUP,
+       RDMA_CQ_DISABLE,
+       RDMA_CTRL_QP_SETUP,
+       RDMA_GET_MEM,
+};
+
+/*
+ * Structure used to describe a TID range.  Valid TIDs are [base, base+num).
+ */
+struct tid_range {
+       unsigned int base;      /* first TID */
+       unsigned int num;       /* number of TIDs in range */
+};
+
+/*
+ * Structure used to request the size and contents of the MTU table.
+ */
+struct mtutab {
+       unsigned int size;      /* # of entries in the MTU table */
+       const unsigned short *mtus;     /* the MTU table values */
+};
+
+struct net_device;
+
+/*
+ * Structure used to request the adapter net_device owning a given MAC address.
+ */
+struct iff_mac {
+       struct net_device *dev; /* the net_device */
+       const unsigned char *mac_addr;  /* MAC address to lookup */
+       u16 vlan_tag;
+};
+
+struct pci_dev;
+
+/*
+ * Structure used to request the TCP DDP parameters.
+ */
+struct ddp_params {
+       unsigned int llimit;    /* TDDP region start address */
+       unsigned int ulimit;    /* TDDP region end address */
+       unsigned int tag_mask;  /* TDDP tag mask */
+       struct pci_dev *pdev;
+};
+
+struct adap_ports {
+       unsigned int nports;    /* number of ports on this adapter */
+       struct net_device *lldevs[2];
+};
+
+/*
+ * Structure used to return information to the iscsi layer.
+ */
+struct ulp_iscsi_info {
+       unsigned int offset;
+       unsigned int llimit;
+       unsigned int ulimit;
+       unsigned int tagmask;
+       unsigned int pgsz3;
+       unsigned int pgsz2;
+       unsigned int pgsz1;
+       unsigned int pgsz0;
+       unsigned int max_rxsz;
+       unsigned int max_txsz;
+       struct pci_dev *pdev;
+};
+
+/*
+ * Structure used to return information to the RDMA layer.
+ */
+struct rdma_info {
+       unsigned int tpt_base;  /* TPT base address */
+       unsigned int tpt_top;   /* TPT last entry address */
+       unsigned int pbl_base;  /* PBL base address */
+       unsigned int pbl_top;   /* PBL last entry address */
+       unsigned int rqt_base;  /* RQT base address */
+       unsigned int rqt_top;   /* RQT last entry address */
+       unsigned int udbell_len;        /* user doorbell region length */
+       unsigned long udbell_physbase;  /* user doorbell physical start addr */
+       void __iomem *kdb_addr; /* kernel doorbell register address */
+       struct pci_dev *pdev;   /* associated PCI device */
+};
+
+/*
+ * Structure used to request an operation on an RDMA completion queue.
+ */
+struct rdma_cq_op {
+       unsigned int id;
+       unsigned int op;
+       unsigned int credits;
+};
+
+/*
+ * Structure used to setup RDMA completion queues.
+ */
+struct rdma_cq_setup {
+       unsigned int id;
+       unsigned long long base_addr;
+       unsigned int size;
+       unsigned int credits;
+       unsigned int credit_thres;
+       unsigned int ovfl_mode;
+};
+
+/*
+ * Structure used to setup the RDMA control egress context.
+ */
+struct rdma_ctrlqp_setup {
+       unsigned long long base_addr;
+       unsigned int size;
+};
+#endif                         /* _CXGB3_OFFLOAD_CTL_DEFS_H */
diff --git a/drivers/net/cxgb3/cxgb3_defs.h b/drivers/net/cxgb3/cxgb3_defs.h
new file mode 100644 (file)
index 0000000..16e0049
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CHELSIO_DEFS_H
+#define _CHELSIO_DEFS_H
+
+#include <linux/skbuff.h>
+#include <net/tcp.h>
+
+#include "t3cdev.h"
+
+#include "cxgb3_offload.h"
+
+#define VALIDATE_TID 1
+
+void *cxgb_alloc_mem(unsigned long size);
+void cxgb_free_mem(void *addr);
+void cxgb_neigh_update(struct neighbour *neigh);
+void cxgb_redirect(struct dst_entry *old, struct dst_entry *new);
+
+/*
+ * Map an ATID or STID to their entries in the corresponding TID tables.
+ */
+static inline union active_open_entry *atid2entry(const struct tid_info *t,
+                                                 unsigned int atid)
+{
+       return &t->atid_tab[atid - t->atid_base];
+}
+
+static inline union listen_entry *stid2entry(const struct tid_info *t,
+                                            unsigned int stid)
+{
+       return &t->stid_tab[stid - t->stid_base];
+}
+
+/*
+ * Find the connection corresponding to a TID.
+ */
+static inline struct t3c_tid_entry *lookup_tid(const struct tid_info *t,
+                                              unsigned int tid)
+{
+       return tid < t->ntids ? &(t->tid_tab[tid]) : NULL;
+}
+
+/*
+ * Find the connection corresponding to a server TID.
+ */
+static inline struct t3c_tid_entry *lookup_stid(const struct tid_info *t,
+                                               unsigned int tid)
+{
+       if (tid < t->stid_base || tid >= t->stid_base + t->nstids)
+               return NULL;
+       return &(stid2entry(t, tid)->t3c_tid);
+}
+
+/*
+ * Find the connection corresponding to an active-open TID.
+ */
+static inline struct t3c_tid_entry *lookup_atid(const struct tid_info *t,
+                                               unsigned int tid)
+{
+       if (tid < t->atid_base || tid >= t->atid_base + t->natids)
+               return NULL;
+       return &(atid2entry(t, tid)->t3c_tid);
+}
+
+int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n);
+int attach_t3cdev(struct t3cdev *dev);
+void detach_t3cdev(struct t3cdev *dev);
+#endif
diff --git a/drivers/net/cxgb3/cxgb3_ioctl.h b/drivers/net/cxgb3/cxgb3_ioctl.h
new file mode 100644 (file)
index 0000000..a942818
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef __CHIOCTL_H__
+#define __CHIOCTL_H__
+
+/*
+ * Ioctl commands specific to this driver.
+ */
+enum {
+       CHELSIO_SETREG = 1024,
+       CHELSIO_GETREG,
+       CHELSIO_SETTPI,
+       CHELSIO_GETTPI,
+       CHELSIO_GETMTUTAB,
+       CHELSIO_SETMTUTAB,
+       CHELSIO_GETMTU,
+       CHELSIO_SET_PM,
+       CHELSIO_GET_PM,
+       CHELSIO_GET_TCAM,
+       CHELSIO_SET_TCAM,
+       CHELSIO_GET_TCB,
+       CHELSIO_GET_MEM,
+       CHELSIO_LOAD_FW,
+       CHELSIO_GET_PROTO,
+       CHELSIO_SET_PROTO,
+       CHELSIO_SET_TRACE_FILTER,
+       CHELSIO_SET_QSET_PARAMS,
+       CHELSIO_GET_QSET_PARAMS,
+       CHELSIO_SET_QSET_NUM,
+       CHELSIO_GET_QSET_NUM,
+       CHELSIO_SET_PKTSCHED,
+};
+
+struct ch_reg {
+       uint32_t cmd;
+       uint32_t addr;
+       uint32_t val;
+};
+
+struct ch_cntxt {
+       uint32_t cmd;
+       uint32_t cntxt_type;
+       uint32_t cntxt_id;
+       uint32_t data[4];
+};
+
+/* context types */
+enum { CNTXT_TYPE_EGRESS, CNTXT_TYPE_FL, CNTXT_TYPE_RSP, CNTXT_TYPE_CQ };
+
+struct ch_desc {
+       uint32_t cmd;
+       uint32_t queue_num;
+       uint32_t idx;
+       uint32_t size;
+       uint8_t data[128];
+};
+
+struct ch_mem_range {
+       uint32_t cmd;
+       uint32_t mem_id;
+       uint32_t addr;
+       uint32_t len;
+       uint32_t version;
+       uint8_t buf[0];
+};
+
+struct ch_qset_params {
+       uint32_t cmd;
+       uint32_t qset_idx;
+       int32_t txq_size[3];
+       int32_t rspq_size;
+       int32_t fl_size[2];
+       int32_t intr_lat;
+       int32_t polling;
+       int32_t cong_thres;
+};
+
+struct ch_pktsched_params {
+       uint32_t cmd;
+       uint8_t sched;
+       uint8_t idx;
+       uint8_t min;
+       uint8_t max;
+       uint8_t binding;
+};
+
+#ifndef TCB_SIZE
+# define TCB_SIZE   128
+#endif
+
+/* TCB size in 32-bit words */
+#define TCB_WORDS (TCB_SIZE / 4)
+
+enum { MEM_CM, MEM_PMRX, MEM_PMTX };   /* ch_mem_range.mem_id values */
+
+struct ch_mtus {
+       uint32_t cmd;
+       uint32_t nmtus;
+       uint16_t mtus[NMTUS];
+};
+
+struct ch_pm {
+       uint32_t cmd;
+       uint32_t tx_pg_sz;
+       uint32_t tx_num_pg;
+       uint32_t rx_pg_sz;
+       uint32_t rx_num_pg;
+       uint32_t pm_total;
+};
+
+struct ch_tcam {
+       uint32_t cmd;
+       uint32_t tcam_size;
+       uint32_t nservers;
+       uint32_t nroutes;
+       uint32_t nfilters;
+};
+
+struct ch_tcb {
+       uint32_t cmd;
+       uint32_t tcb_index;
+       uint32_t tcb_data[TCB_WORDS];
+};
+
+struct ch_tcam_word {
+       uint32_t cmd;
+       uint32_t addr;
+       uint32_t buf[3];
+};
+
+struct ch_trace {
+       uint32_t cmd;
+       uint32_t sip;
+       uint32_t sip_mask;
+       uint32_t dip;
+       uint32_t dip_mask;
+       uint16_t sport;
+       uint16_t sport_mask;
+       uint16_t dport;
+       uint16_t dport_mask;
+       uint32_t vlan:12;
+       uint32_t vlan_mask:12;
+       uint32_t intf:4;
+       uint32_t intf_mask:4;
+       uint8_t proto;
+       uint8_t proto_mask;
+       uint8_t invert_match:1;
+       uint8_t config_tx:1;
+       uint8_t config_rx:1;
+       uint8_t trace_tx:1;
+       uint8_t trace_rx:1;
+};
+
+#define SIOCCHIOCTL SIOCDEVPRIVATE
+
+#endif
diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c
new file mode 100644 (file)
index 0000000..dfa035a
--- /dev/null
@@ -0,0 +1,2515 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/mii.h>
+#include <linux/sockios.h>
+#include <linux/workqueue.h>
+#include <linux/proc_fs.h>
+#include <linux/rtnetlink.h>
+#include <asm/uaccess.h>
+
+#include "common.h"
+#include "cxgb3_ioctl.h"
+#include "regs.h"
+#include "cxgb3_offload.h"
+#include "version.h"
+
+#include "cxgb3_ctl_defs.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+enum {
+       MAX_TXQ_ENTRIES = 16384,
+       MAX_CTRL_TXQ_ENTRIES = 1024,
+       MAX_RSPQ_ENTRIES = 16384,
+       MAX_RX_BUFFERS = 16384,
+       MAX_RX_JUMBO_BUFFERS = 16384,
+       MIN_TXQ_ENTRIES = 4,
+       MIN_CTRL_TXQ_ENTRIES = 4,
+       MIN_RSPQ_ENTRIES = 32,
+       MIN_FL_ENTRIES = 32
+};
+
+#define PORT_MASK ((1 << MAX_NPORTS) - 1)
+
+#define DFLT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK | \
+                        NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP |\
+                        NETIF_MSG_RX_ERR | NETIF_MSG_TX_ERR)
+
+#define EEPROM_MAGIC 0x38E2F10C
+
+#define to_net_dev(class) container_of(class, struct net_device, class_dev)
+
+#define CH_DEVICE(devid, ssid, idx) \
+       { PCI_VENDOR_ID_CHELSIO, devid, PCI_ANY_ID, ssid, 0, 0, idx }
+
+static const struct pci_device_id cxgb3_pci_tbl[] = {
+       CH_DEVICE(0x20, 1, 0),  /* PE9000 */
+       CH_DEVICE(0x21, 1, 1),  /* T302E */
+       CH_DEVICE(0x22, 1, 2),  /* T310E */
+       CH_DEVICE(0x23, 1, 3),  /* T320X */
+       CH_DEVICE(0x24, 1, 1),  /* T302X */
+       CH_DEVICE(0x25, 1, 3),  /* T320E */
+       CH_DEVICE(0x26, 1, 2),  /* T310X */
+       CH_DEVICE(0x30, 1, 2),  /* T3B10 */
+       CH_DEVICE(0x31, 1, 3),  /* T3B20 */
+       CH_DEVICE(0x32, 1, 1),  /* T3B02 */
+       {0,}
+};
+
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_AUTHOR("Chelsio Communications");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_DEVICE_TABLE(pci, cxgb3_pci_tbl);
+
+static int dflt_msg_enable = DFLT_MSG_ENABLE;
+
+module_param(dflt_msg_enable, int, 0644);
+MODULE_PARM_DESC(dflt_msg_enable, "Chelsio T3 default message enable bitmap");
+
+/*
+ * The driver uses the best interrupt scheme available on a platform in the
+ * order MSI-X, MSI, legacy pin interrupts.  This parameter determines which
+ * of these schemes the driver may consider as follows:
+ *
+ * msi = 2: choose from among all three options
+ * msi = 1: only consider MSI and pin interrupts
+ * msi = 0: force pin interrupts
+ */
+static int msi = 2;
+
+module_param(msi, int, 0644);
+MODULE_PARM_DESC(msi, "whether to use MSI or MSI-X");
+
+/*
+ * The driver enables offload as a default.
+ * To disable it, use ofld_disable = 1.
+ */
+
+static int ofld_disable = 0;
+
+module_param(ofld_disable, int, 0644);
+MODULE_PARM_DESC(ofld_disable, "whether to enable offload at init time or not");
+
+/*
+ * We have work elements that we need to cancel when an interface is taken
+ * down.  Normally the work elements would be executed by keventd but that
+ * can deadlock because of linkwatch.  If our close method takes the rtnl
+ * lock and linkwatch is ahead of our work elements in keventd, linkwatch
+ * will block keventd as it needs the rtnl lock, and we'll deadlock waiting
+ * for our work to complete.  Get our own work queue to solve this.
+ */
+static struct workqueue_struct *cxgb3_wq;
+
+/**
+ *     link_report - show link status and link speed/duplex
+ *     @p: the port whose settings are to be reported
+ *
+ *     Shows the link status, speed, and duplex of a port.
+ */
+static void link_report(struct net_device *dev)
+{
+       if (!netif_carrier_ok(dev))
+               printk(KERN_INFO "%s: link down\n", dev->name);
+       else {
+               const char *s = "10Mbps";
+               const struct port_info *p = netdev_priv(dev);
+
+               switch (p->link_config.speed) {
+               case SPEED_10000:
+                       s = "10Gbps";
+                       break;
+               case SPEED_1000:
+                       s = "1000Mbps";
+                       break;
+               case SPEED_100:
+                       s = "100Mbps";
+                       break;
+               }
+
+               printk(KERN_INFO "%s: link up, %s, %s-duplex\n", dev->name, s,
+                      p->link_config.duplex == DUPLEX_FULL ? "full" : "half");
+       }
+}
+
+/**
+ *     t3_os_link_changed - handle link status changes
+ *     @adapter: the adapter associated with the link change
+ *     @port_id: the port index whose limk status has changed
+ *     @link_stat: the new status of the link
+ *     @speed: the new speed setting
+ *     @duplex: the new duplex setting
+ *     @pause: the new flow-control setting
+ *
+ *     This is the OS-dependent handler for link status changes.  The OS
+ *     neutral handler takes care of most of the processing for these events,
+ *     then calls this handler for any OS-specific processing.
+ */
+void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
+                       int speed, int duplex, int pause)
+{
+       struct net_device *dev = adapter->port[port_id];
+
+       /* Skip changes from disabled ports. */
+       if (!netif_running(dev))
+               return;
+
+       if (link_stat != netif_carrier_ok(dev)) {
+               if (link_stat)
+                       netif_carrier_on(dev);
+               else
+                       netif_carrier_off(dev);
+               link_report(dev);
+       }
+}
+
+static void cxgb_set_rxmode(struct net_device *dev)
+{
+       struct t3_rx_mode rm;
+       struct port_info *pi = netdev_priv(dev);
+
+       init_rx_mode(&rm, dev, dev->mc_list);
+       t3_mac_set_rx_mode(&pi->mac, &rm);
+}
+
+/**
+ *     link_start - enable a port
+ *     @dev: the device to enable
+ *
+ *     Performs the MAC and PHY actions needed to enable a port.
+ */
+static void link_start(struct net_device *dev)
+{
+       struct t3_rx_mode rm;
+       struct port_info *pi = netdev_priv(dev);
+       struct cmac *mac = &pi->mac;
+
+       init_rx_mode(&rm, dev, dev->mc_list);
+       t3_mac_reset(mac);
+       t3_mac_set_mtu(mac, dev->mtu);
+       t3_mac_set_address(mac, 0, dev->dev_addr);
+       t3_mac_set_rx_mode(mac, &rm);
+       t3_link_start(&pi->phy, mac, &pi->link_config);
+       t3_mac_enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
+}
+
+static inline void cxgb_disable_msi(struct adapter *adapter)
+{
+       if (adapter->flags & USING_MSIX) {
+               pci_disable_msix(adapter->pdev);
+               adapter->flags &= ~USING_MSIX;
+       } else if (adapter->flags & USING_MSI) {
+               pci_disable_msi(adapter->pdev);
+               adapter->flags &= ~USING_MSI;
+       }
+}
+
+/*
+ * Interrupt handler for asynchronous events used with MSI-X.
+ */
+static irqreturn_t t3_async_intr_handler(int irq, void *cookie)
+{
+       t3_slow_intr_handler(cookie);
+       return IRQ_HANDLED;
+}
+
+/*
+ * Name the MSI-X interrupts.
+ */
+static void name_msix_vecs(struct adapter *adap)
+{
+       int i, j, msi_idx = 1, n = sizeof(adap->msix_info[0].desc) - 1;
+
+       snprintf(adap->msix_info[0].desc, n, "%s", adap->name);
+       adap->msix_info[0].desc[n] = 0;
+
+       for_each_port(adap, j) {
+               struct net_device *d = adap->port[j];
+               const struct port_info *pi = netdev_priv(d);
+
+               for (i = 0; i < pi->nqsets; i++, msi_idx++) {
+                       snprintf(adap->msix_info[msi_idx].desc, n,
+                                "%s (queue %d)", d->name, i);
+                       adap->msix_info[msi_idx].desc[n] = 0;
+               }
+       }
+}
+
+static int request_msix_data_irqs(struct adapter *adap)
+{
+       int i, j, err, qidx = 0;
+
+       for_each_port(adap, i) {
+               int nqsets = adap2pinfo(adap, i)->nqsets;
+
+               for (j = 0; j < nqsets; ++j) {
+                       err = request_irq(adap->msix_info[qidx + 1].vec,
+                                         t3_intr_handler(adap,
+                                                         adap->sge.qs[qidx].
+                                                         rspq.polling), 0,
+                                         adap->msix_info[qidx + 1].desc,
+                                         &adap->sge.qs[qidx]);
+                       if (err) {
+                               while (--qidx >= 0)
+                                       free_irq(adap->msix_info[qidx + 1].vec,
+                                                &adap->sge.qs[qidx]);
+                               return err;
+                       }
+                       qidx++;
+               }
+       }
+       return 0;
+}
+
+/**
+ *     setup_rss - configure RSS
+ *     @adap: the adapter
+ *
+ *     Sets up RSS to distribute packets to multiple receive queues.  We
+ *     configure the RSS CPU lookup table to distribute to the number of HW
+ *     receive queues, and the response queue lookup table to narrow that
+ *     down to the response queues actually configured for each port.
+ *     We always configure the RSS mapping for two ports since the mapping
+ *     table has plenty of entries.
+ */
+static void setup_rss(struct adapter *adap)
+{
+       int i;
+       unsigned int nq0 = adap2pinfo(adap, 0)->nqsets;
+       unsigned int nq1 = adap->port[1] ? adap2pinfo(adap, 1)->nqsets : 1;
+       u8 cpus[SGE_QSETS + 1];
+       u16 rspq_map[RSS_TABLE_SIZE];
+
+       for (i = 0; i < SGE_QSETS; ++i)
+               cpus[i] = i;
+       cpus[SGE_QSETS] = 0xff; /* terminator */
+
+       for (i = 0; i < RSS_TABLE_SIZE / 2; ++i) {
+               rspq_map[i] = i % nq0;
+               rspq_map[i + RSS_TABLE_SIZE / 2] = (i % nq1) + nq0;
+       }
+
+       t3_config_rss(adap, F_RQFEEDBACKENABLE | F_TNLLKPEN | F_TNLMAPEN |
+                     F_TNLPRTEN | F_TNL2TUPEN | F_TNL4TUPEN |
+                     V_RRCPLCPUSIZE(6), cpus, rspq_map);
+}
+
+/*
+ * If we have multiple receive queues per port serviced by NAPI we need one
+ * netdevice per queue as NAPI operates on netdevices.  We already have one
+ * netdevice, namely the one associated with the interface, so we use dummy
+ * ones for any additional queues.  Note that these netdevices exist purely
+ * so that NAPI has something to work with, they do not represent network
+ * ports and are not registered.
+ */
+static int init_dummy_netdevs(struct adapter *adap)
+{
+       int i, j, dummy_idx = 0;
+       struct net_device *nd;
+
+       for_each_port(adap, i) {
+               struct net_device *dev = adap->port[i];
+               const struct port_info *pi = netdev_priv(dev);
+
+               for (j = 0; j < pi->nqsets - 1; j++) {
+                       if (!adap->dummy_netdev[dummy_idx]) {
+                               nd = alloc_netdev(0, "", ether_setup);
+                               if (!nd)
+                                       goto free_all;
+
+                               nd->priv = adap;
+                               nd->weight = 64;
+                               set_bit(__LINK_STATE_START, &nd->state);
+                               adap->dummy_netdev[dummy_idx] = nd;
+                       }
+                       strcpy(adap->dummy_netdev[dummy_idx]->name, dev->name);
+                       dummy_idx++;
+               }
+       }
+       return 0;
+
+free_all:
+       while (--dummy_idx >= 0) {
+               free_netdev(adap->dummy_netdev[dummy_idx]);
+               adap->dummy_netdev[dummy_idx] = NULL;
+       }
+       return -ENOMEM;
+}
+
+/*
+ * Wait until all NAPI handlers are descheduled.  This includes the handlers of
+ * both netdevices representing interfaces and the dummy ones for the extra
+ * queues.
+ */
+static void quiesce_rx(struct adapter *adap)
+{
+       int i;
+       struct net_device *dev;
+
+       for_each_port(adap, i) {
+               dev = adap->port[i];
+               while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
+                       msleep(1);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(adap->dummy_netdev); i++) {
+               dev = adap->dummy_netdev[i];
+               if (dev)
+                       while (test_bit(__LINK_STATE_RX_SCHED, &dev->state))
+                               msleep(1);
+       }
+}
+
+/**
+ *     setup_sge_qsets - configure SGE Tx/Rx/response queues
+ *     @adap: the adapter
+ *
+ *     Determines how many sets of SGE queues to use and initializes them.
+ *     We support multiple queue sets per port if we have MSI-X, otherwise
+ *     just one queue set per port.
+ */
+static int setup_sge_qsets(struct adapter *adap)
+{
+       int i, j, err, irq_idx = 0, qset_idx = 0, dummy_dev_idx = 0;
+       unsigned int ntxq = is_offload(adap) ? SGE_TXQ_PER_SET : 1;
+
+       if (adap->params.rev > 0 && !(adap->flags & USING_MSI))
+               irq_idx = -1;
+
+       for_each_port(adap, i) {
+               struct net_device *dev = adap->port[i];
+               const struct port_info *pi = netdev_priv(dev);
+
+               for (j = 0; j < pi->nqsets; ++j, ++qset_idx) {
+                       err = t3_sge_alloc_qset(adap, qset_idx, 1,
+                               (adap->flags & USING_MSIX) ? qset_idx + 1 :
+                                                            irq_idx,
+                               &adap->params.sge.qset[qset_idx], ntxq,
+                               j == 0 ? dev :
+                                        adap-> dummy_netdev[dummy_dev_idx++]);
+                       if (err) {
+                               t3_free_sge_resources(adap);
+                               return err;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static ssize_t attr_show(struct class_device *cd, char *buf,
+                        ssize_t(*format) (struct adapter *, char *))
+{
+       ssize_t len;
+       struct adapter *adap = to_net_dev(cd)->priv;
+
+       /* Synchronize with ioctls that may shut down the device */
+       rtnl_lock();
+       len = (*format) (adap, buf);
+       rtnl_unlock();
+       return len;
+}
+
+static ssize_t attr_store(struct class_device *cd, const char *buf, size_t len,
+                         ssize_t(*set) (struct adapter *, unsigned int),
+                         unsigned int min_val, unsigned int max_val)
+{
+       char *endp;
+       ssize_t ret;
+       unsigned int val;
+       struct adapter *adap = to_net_dev(cd)->priv;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       val = simple_strtoul(buf, &endp, 0);
+       if (endp == buf || val < min_val || val > max_val)
+               return -EINVAL;
+
+       rtnl_lock();
+       ret = (*set) (adap, val);
+       if (!ret)
+               ret = len;
+       rtnl_unlock();
+       return ret;
+}
+
+#define CXGB3_SHOW(name, val_expr) \
+static ssize_t format_##name(struct adapter *adap, char *buf) \
+{ \
+       return sprintf(buf, "%u\n", val_expr); \
+} \
+static ssize_t show_##name(struct class_device *cd, char *buf) \
+{ \
+       return attr_show(cd, buf, format_##name); \
+}
+
+static ssize_t set_nfilters(struct adapter *adap, unsigned int val)
+{
+       if (adap->flags & FULL_INIT_DONE)
+               return -EBUSY;
+       if (val && adap->params.rev == 0)
+               return -EINVAL;
+       if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers)
+               return -EINVAL;
+       adap->params.mc5.nfilters = val;
+       return 0;
+}
+
+static ssize_t store_nfilters(struct class_device *cd, const char *buf,
+                             size_t len)
+{
+       return attr_store(cd, buf, len, set_nfilters, 0, ~0);
+}
+
+static ssize_t set_nservers(struct adapter *adap, unsigned int val)
+{
+       if (adap->flags & FULL_INIT_DONE)
+               return -EBUSY;
+       if (val > t3_mc5_size(&adap->mc5) - adap->params.mc5.nfilters)
+               return -EINVAL;
+       adap->params.mc5.nservers = val;
+       return 0;
+}
+
+static ssize_t store_nservers(struct class_device *cd, const char *buf,
+                             size_t len)
+{
+       return attr_store(cd, buf, len, set_nservers, 0, ~0);
+}
+
+#define CXGB3_ATTR_R(name, val_expr) \
+CXGB3_SHOW(name, val_expr) \
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+
+#define CXGB3_ATTR_RW(name, val_expr, store_method) \
+CXGB3_SHOW(name, val_expr) \
+static CLASS_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_method)
+
+CXGB3_ATTR_R(cam_size, t3_mc5_size(&adap->mc5));
+CXGB3_ATTR_RW(nfilters, adap->params.mc5.nfilters, store_nfilters);
+CXGB3_ATTR_RW(nservers, adap->params.mc5.nservers, store_nservers);
+
+static struct attribute *cxgb3_attrs[] = {
+       &class_device_attr_cam_size.attr,
+       &class_device_attr_nfilters.attr,
+       &class_device_attr_nservers.attr,
+       NULL
+};
+
+static struct attribute_group cxgb3_attr_group = {.attrs = cxgb3_attrs };
+
+static ssize_t tm_attr_show(struct class_device *cd, char *buf, int sched)
+{
+       ssize_t len;
+       unsigned int v, addr, bpt, cpt;
+       struct adapter *adap = to_net_dev(cd)->priv;
+
+       addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
+       rtnl_lock();
+       t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
+       v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
+       if (sched & 1)
+               v >>= 16;
+       bpt = (v >> 8) & 0xff;
+       cpt = v & 0xff;
+       if (!cpt)
+               len = sprintf(buf, "disabled\n");
+       else {
+               v = (adap->params.vpd.cclk * 1000) / cpt;
+               len = sprintf(buf, "%u Kbps\n", (v * bpt) / 125);
+       }
+       rtnl_unlock();
+       return len;
+}
+
+static ssize_t tm_attr_store(struct class_device *cd, const char *buf,
+                            size_t len, int sched)
+{
+       char *endp;
+       ssize_t ret;
+       unsigned int val;
+       struct adapter *adap = to_net_dev(cd)->priv;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       val = simple_strtoul(buf, &endp, 0);
+       if (endp == buf || val > 10000000)
+               return -EINVAL;
+
+       rtnl_lock();
+       ret = t3_config_sched(adap, val, sched);
+       if (!ret)
+               ret = len;
+       rtnl_unlock();
+       return ret;
+}
+
+#define TM_ATTR(name, sched) \
+static ssize_t show_##name(struct class_device *cd, char *buf) \
+{ \
+       return tm_attr_show(cd, buf, sched); \
+} \
+static ssize_t store_##name(struct class_device *cd, const char *buf, size_t len) \
+{ \
+       return tm_attr_store(cd, buf, len, sched); \
+} \
+static CLASS_DEVICE_ATTR(name, S_IRUGO | S_IWUSR, show_##name, store_##name)
+
+TM_ATTR(sched0, 0);
+TM_ATTR(sched1, 1);
+TM_ATTR(sched2, 2);
+TM_ATTR(sched3, 3);
+TM_ATTR(sched4, 4);
+TM_ATTR(sched5, 5);
+TM_ATTR(sched6, 6);
+TM_ATTR(sched7, 7);
+
+static struct attribute *offload_attrs[] = {
+       &class_device_attr_sched0.attr,
+       &class_device_attr_sched1.attr,
+       &class_device_attr_sched2.attr,
+       &class_device_attr_sched3.attr,
+       &class_device_attr_sched4.attr,
+       &class_device_attr_sched5.attr,
+       &class_device_attr_sched6.attr,
+       &class_device_attr_sched7.attr,
+       NULL
+};
+
+static struct attribute_group offload_attr_group = {.attrs = offload_attrs };
+
+/*
+ * Sends an sk_buff to an offload queue driver
+ * after dealing with any active network taps.
+ */
+static inline int offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
+{
+       int ret;
+
+       local_bh_disable();
+       ret = t3_offload_tx(tdev, skb);
+       local_bh_enable();
+       return ret;
+}
+
+static int write_smt_entry(struct adapter *adapter, int idx)
+{
+       struct cpl_smt_write_req *req;
+       struct sk_buff *skb = alloc_skb(sizeof(*req), GFP_KERNEL);
+
+       if (!skb)
+               return -ENOMEM;
+
+       req = (struct cpl_smt_write_req *)__skb_put(skb, sizeof(*req));
+       req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+       OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SMT_WRITE_REQ, idx));
+       req->mtu_idx = NMTUS - 1;       /* should be 0 but there's a T3 bug */
+       req->iff = idx;
+       memset(req->src_mac1, 0, sizeof(req->src_mac1));
+       memcpy(req->src_mac0, adapter->port[idx]->dev_addr, ETH_ALEN);
+       skb->priority = 1;
+       offload_tx(&adapter->tdev, skb);
+       return 0;
+}
+
+static int init_smt(struct adapter *adapter)
+{
+       int i;
+
+       for_each_port(adapter, i)
+           write_smt_entry(adapter, i);
+       return 0;
+}
+
+static void init_port_mtus(struct adapter *adapter)
+{
+       unsigned int mtus = adapter->port[0]->mtu;
+
+       if (adapter->port[1])
+               mtus |= adapter->port[1]->mtu << 16;
+       t3_write_reg(adapter, A_TP_MTU_PORT_TABLE, mtus);
+}
+
+static void send_pktsched_cmd(struct adapter *adap, int sched, int qidx, int lo,
+                             int hi, int port)
+{
+       struct sk_buff *skb;
+       struct mngt_pktsched_wr *req;
+
+       skb = alloc_skb(sizeof(*req), GFP_KERNEL | __GFP_NOFAIL);
+       req = (struct mngt_pktsched_wr *)skb_put(skb, sizeof(*req));
+       req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_MNGT));
+       req->mngt_opcode = FW_MNGTOPCODE_PKTSCHED_SET;
+       req->sched = sched;
+       req->idx = qidx;
+       req->min = lo;
+       req->max = hi;
+       req->binding = port;
+       t3_mgmt_tx(adap, skb);
+}
+
+static void bind_qsets(struct adapter *adap)
+{
+       int i, j;
+
+       for_each_port(adap, i) {
+               const struct port_info *pi = adap2pinfo(adap, i);
+
+               for (j = 0; j < pi->nqsets; ++j)
+                       send_pktsched_cmd(adap, 1, pi->first_qset + j, -1,
+                                         -1, i);
+       }
+}
+
+/**
+ *     cxgb_up - enable the adapter
+ *     @adapter: adapter being enabled
+ *
+ *     Called when the first port is enabled, this function performs the
+ *     actions necessary to make an adapter operational, such as completing
+ *     the initialization of HW modules, and enabling interrupts.
+ *
+ *     Must be called with the rtnl lock held.
+ */
+static int cxgb_up(struct adapter *adap)
+{
+       int err = 0;
+
+       if (!(adap->flags & FULL_INIT_DONE)) {
+               err = t3_check_fw_version(adap);
+               if (err)
+                       goto out;
+
+               err = init_dummy_netdevs(adap);
+               if (err)
+                       goto out;
+
+               err = t3_init_hw(adap, 0);
+               if (err)
+                       goto out;
+
+               err = setup_sge_qsets(adap);
+               if (err)
+                       goto out;
+
+               setup_rss(adap);
+               adap->flags |= FULL_INIT_DONE;
+       }
+
+       t3_intr_clear(adap);
+
+       if (adap->flags & USING_MSIX) {
+               name_msix_vecs(adap);
+               err = request_irq(adap->msix_info[0].vec,
+                                 t3_async_intr_handler, 0,
+                                 adap->msix_info[0].desc, adap);
+               if (err)
+                       goto irq_err;
+
+               if (request_msix_data_irqs(adap)) {
+                       free_irq(adap->msix_info[0].vec, adap);
+                       goto irq_err;
+               }
+       } else if ((err = request_irq(adap->pdev->irq,
+                                     t3_intr_handler(adap,
+                                                     adap->sge.qs[0].rspq.
+                                                     polling),
+                                     (adap->flags & USING_MSI) ? 0 : SA_SHIRQ,
+                                     adap->name, adap)))
+               goto irq_err;
+
+       t3_sge_start(adap);
+       t3_intr_enable(adap);
+
+       if ((adap->flags & (USING_MSIX | QUEUES_BOUND)) == USING_MSIX)
+               bind_qsets(adap);
+       adap->flags |= QUEUES_BOUND;
+
+out:
+       return err;
+irq_err:
+       CH_ERR(adap, "request_irq failed, err %d\n", err);
+       goto out;
+}
+
+/*
+ * Release resources when all the ports and offloading have been stopped.
+ */
+static void cxgb_down(struct adapter *adapter)
+{
+       t3_sge_stop(adapter);
+       spin_lock_irq(&adapter->work_lock);     /* sync with PHY intr task */
+       t3_intr_disable(adapter);
+       spin_unlock_irq(&adapter->work_lock);
+
+       if (adapter->flags & USING_MSIX) {
+               int i, n = 0;
+
+               free_irq(adapter->msix_info[0].vec, adapter);
+               for_each_port(adapter, i)
+                   n += adap2pinfo(adapter, i)->nqsets;
+
+               for (i = 0; i < n; ++i)
+                       free_irq(adapter->msix_info[i + 1].vec,
+                                &adapter->sge.qs[i]);
+       } else
+               free_irq(adapter->pdev->irq, adapter);
+
+       flush_workqueue(cxgb3_wq);      /* wait for external IRQ handler */
+       quiesce_rx(adapter);
+}
+
+static void schedule_chk_task(struct adapter *adap)
+{
+       unsigned int timeo;
+
+       timeo = adap->params.linkpoll_period ?
+           (HZ * adap->params.linkpoll_period) / 10 :
+           adap->params.stats_update_period * HZ;
+       if (timeo)
+               queue_delayed_work(cxgb3_wq, &adap->adap_check_task, timeo);
+}
+
+static int offload_open(struct net_device *dev)
+{
+       struct adapter *adapter = dev->priv;
+       struct t3cdev *tdev = T3CDEV(dev);
+       int adap_up = adapter->open_device_map & PORT_MASK;
+       int err = 0;
+
+       if (test_and_set_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
+               return 0;
+
+       if (!adap_up && (err = cxgb_up(adapter)) < 0)
+               return err;
+
+       t3_tp_set_offload_mode(adapter, 1);
+       tdev->lldev = adapter->port[0];
+       err = cxgb3_offload_activate(adapter);
+       if (err)
+               goto out;
+
+       init_port_mtus(adapter);
+       t3_load_mtus(adapter, adapter->params.mtus, adapter->params.a_wnd,
+                    adapter->params.b_wnd,
+                    adapter->params.rev == 0 ?
+                    adapter->port[0]->mtu : 0xffff);
+       init_smt(adapter);
+
+       /* Never mind if the next step fails */
+       sysfs_create_group(&tdev->lldev->class_dev.kobj, &offload_attr_group);
+
+       /* Call back all registered clients */
+       cxgb3_add_clients(tdev);
+
+out:
+       /* restore them in case the offload module has changed them */
+       if (err) {
+               t3_tp_set_offload_mode(adapter, 0);
+               clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+               cxgb3_set_dummy_ops(tdev);
+       }
+       return err;
+}
+
+static int offload_close(struct t3cdev *tdev)
+{
+       struct adapter *adapter = tdev2adap(tdev);
+
+       if (!test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map))
+               return 0;
+
+       /* Call back all registered clients */
+       cxgb3_remove_clients(tdev);
+
+       sysfs_remove_group(&tdev->lldev->class_dev.kobj, &offload_attr_group);
+
+       tdev->lldev = NULL;
+       cxgb3_set_dummy_ops(tdev);
+       t3_tp_set_offload_mode(adapter, 0);
+       clear_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map);
+
+       if (!adapter->open_device_map)
+               cxgb_down(adapter);
+
+       cxgb3_offload_deactivate(adapter);
+       return 0;
+}
+
+static int cxgb_open(struct net_device *dev)
+{
+       int err;
+       struct adapter *adapter = dev->priv;
+       struct port_info *pi = netdev_priv(dev);
+       int other_ports = adapter->open_device_map & PORT_MASK;
+
+       if (!adapter->open_device_map && (err = cxgb_up(adapter)) < 0)
+               return err;
+
+       set_bit(pi->port_id, &adapter->open_device_map);
+       if (!ofld_disable) {
+               err = offload_open(dev);
+               if (err)
+                       printk(KERN_WARNING
+                              "Could not initialize offload capabilities\n");
+       }
+
+       link_start(dev);
+       t3_port_intr_enable(adapter, pi->port_id);
+       netif_start_queue(dev);
+       if (!other_ports)
+               schedule_chk_task(adapter);
+
+       return 0;
+}
+
+static int cxgb_close(struct net_device *dev)
+{
+       struct adapter *adapter = dev->priv;
+       struct port_info *p = netdev_priv(dev);
+
+       t3_port_intr_disable(adapter, p->port_id);
+       netif_stop_queue(dev);
+       p->phy.ops->power_down(&p->phy, 1);
+       netif_carrier_off(dev);
+       t3_mac_disable(&p->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
+
+       spin_lock(&adapter->work_lock); /* sync with update task */
+       clear_bit(p->port_id, &adapter->open_device_map);
+       spin_unlock(&adapter->work_lock);
+
+       if (!(adapter->open_device_map & PORT_MASK))
+               cancel_rearming_delayed_workqueue(cxgb3_wq,
+                                                 &adapter->adap_check_task);
+
+       if (!adapter->open_device_map)
+               cxgb_down(adapter);
+
+       return 0;
+}
+
+static struct net_device_stats *cxgb_get_stats(struct net_device *dev)
+{
+       struct adapter *adapter = dev->priv;
+       struct port_info *p = netdev_priv(dev);
+       struct net_device_stats *ns = &p->netstats;
+       const struct mac_stats *pstats;
+
+       spin_lock(&adapter->stats_lock);
+       pstats = t3_mac_update_stats(&p->mac);
+       spin_unlock(&adapter->stats_lock);
+
+       ns->tx_bytes = pstats->tx_octets;
+       ns->tx_packets = pstats->tx_frames;
+       ns->rx_bytes = pstats->rx_octets;
+       ns->rx_packets = pstats->rx_frames;
+       ns->multicast = pstats->rx_mcast_frames;
+
+       ns->tx_errors = pstats->tx_underrun;
+       ns->rx_errors = pstats->rx_symbol_errs + pstats->rx_fcs_errs +
+           pstats->rx_too_long + pstats->rx_jabber + pstats->rx_short +
+           pstats->rx_fifo_ovfl;
+
+       /* detailed rx_errors */
+       ns->rx_length_errors = pstats->rx_jabber + pstats->rx_too_long;
+       ns->rx_over_errors = 0;
+       ns->rx_crc_errors = pstats->rx_fcs_errs;
+       ns->rx_frame_errors = pstats->rx_symbol_errs;
+       ns->rx_fifo_errors = pstats->rx_fifo_ovfl;
+       ns->rx_missed_errors = pstats->rx_cong_drops;
+
+       /* detailed tx_errors */
+       ns->tx_aborted_errors = 0;
+       ns->tx_carrier_errors = 0;
+       ns->tx_fifo_errors = pstats->tx_underrun;
+       ns->tx_heartbeat_errors = 0;
+       ns->tx_window_errors = 0;
+       return ns;
+}
+
+static u32 get_msglevel(struct net_device *dev)
+{
+       struct adapter *adapter = dev->priv;
+
+       return adapter->msg_enable;
+}
+
+static void set_msglevel(struct net_device *dev, u32 val)
+{
+       struct adapter *adapter = dev->priv;
+
+       adapter->msg_enable = val;
+}
+
+static char stats_strings[][ETH_GSTRING_LEN] = {
+       "TxOctetsOK         ",
+       "TxFramesOK         ",
+       "TxMulticastFramesOK",
+       "TxBroadcastFramesOK",
+       "TxPauseFrames      ",
+       "TxUnderrun         ",
+       "TxExtUnderrun      ",
+
+       "TxFrames64         ",
+       "TxFrames65To127    ",
+       "TxFrames128To255   ",
+       "TxFrames256To511   ",
+       "TxFrames512To1023  ",
+       "TxFrames1024To1518 ",
+       "TxFrames1519ToMax  ",
+
+       "RxOctetsOK         ",
+       "RxFramesOK         ",
+       "RxMulticastFramesOK",
+       "RxBroadcastFramesOK",
+       "RxPauseFrames      ",
+       "RxFCSErrors        ",
+       "RxSymbolErrors     ",
+       "RxShortErrors      ",
+       "RxJabberErrors     ",
+       "RxLengthErrors     ",
+       "RxFIFOoverflow     ",
+
+       "RxFrames64         ",
+       "RxFrames65To127    ",
+       "RxFrames128To255   ",
+       "RxFrames256To511   ",
+       "RxFrames512To1023  ",
+       "RxFrames1024To1518 ",
+       "RxFrames1519ToMax  ",
+
+       "PhyFIFOErrors      ",
+       "TSO                ",
+       "VLANextractions    ",
+       "VLANinsertions     ",
+       "TxCsumOffload      ",
+       "RxCsumGood         ",
+       "RxDrops            "
+};
+
+static int get_stats_count(struct net_device *dev)
+{
+       return ARRAY_SIZE(stats_strings);
+}
+
+#define T3_REGMAP_SIZE (3 * 1024)
+
+static int get_regs_len(struct net_device *dev)
+{
+       return T3_REGMAP_SIZE;
+}
+
+static int get_eeprom_len(struct net_device *dev)
+{
+       return EEPROMSIZE;
+}
+
+static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
+{
+       u32 fw_vers = 0;
+       struct adapter *adapter = dev->priv;
+
+       t3_get_fw_version(adapter, &fw_vers);
+
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+       strcpy(info->bus_info, pci_name(adapter->pdev));
+       if (!fw_vers)
+               strcpy(info->fw_version, "N/A");
+       else {
+               snprintf(info->fw_version, sizeof(info->fw_version),
+                        "%s %u.%u.%u",
+                        G_FW_VERSION_TYPE(fw_vers) ? "T" : "N",
+                        G_FW_VERSION_MAJOR(fw_vers),
+                        G_FW_VERSION_MINOR(fw_vers),
+                        G_FW_VERSION_MICRO(fw_vers));
+       }
+}
+
+static void get_strings(struct net_device *dev, u32 stringset, u8 * data)
+{
+       if (stringset == ETH_SS_STATS)
+               memcpy(data, stats_strings, sizeof(stats_strings));
+}
+
+static unsigned long collect_sge_port_stats(struct adapter *adapter,
+                                           struct port_info *p, int idx)
+{
+       int i;
+       unsigned long tot = 0;
+
+       for (i = 0; i < p->nqsets; ++i)
+               tot += adapter->sge.qs[i + p->first_qset].port_stats[idx];
+       return tot;
+}
+
+static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
+                     u64 *data)
+{
+       struct adapter *adapter = dev->priv;
+       struct port_info *pi = netdev_priv(dev);
+       const struct mac_stats *s;
+
+       spin_lock(&adapter->stats_lock);
+       s = t3_mac_update_stats(&pi->mac);
+       spin_unlock(&adapter->stats_lock);
+
+       *data++ = s->tx_octets;
+       *data++ = s->tx_frames;
+       *data++ = s->tx_mcast_frames;
+       *data++ = s->tx_bcast_frames;
+       *data++ = s->tx_pause;
+       *data++ = s->tx_underrun;
+       *data++ = s->tx_fifo_urun;
+
+       *data++ = s->tx_frames_64;
+       *data++ = s->tx_frames_65_127;
+       *data++ = s->tx_frames_128_255;
+       *data++ = s->tx_frames_256_511;
+       *data++ = s->tx_frames_512_1023;
+       *data++ = s->tx_frames_1024_1518;
+       *data++ = s->tx_frames_1519_max;
+
+       *data++ = s->rx_octets;
+       *data++ = s->rx_frames;
+       *data++ = s->rx_mcast_frames;
+       *data++ = s->rx_bcast_frames;
+       *data++ = s->rx_pause;
+       *data++ = s->rx_fcs_errs;
+       *data++ = s->rx_symbol_errs;
+       *data++ = s->rx_short;
+       *data++ = s->rx_jabber;
+       *data++ = s->rx_too_long;
+       *data++ = s->rx_fifo_ovfl;
+
+       *data++ = s->rx_frames_64;
+       *data++ = s->rx_frames_65_127;
+       *data++ = s->rx_frames_128_255;
+       *data++ = s->rx_frames_256_511;
+       *data++ = s->rx_frames_512_1023;
+       *data++ = s->rx_frames_1024_1518;
+       *data++ = s->rx_frames_1519_max;
+
+       *data++ = pi->phy.fifo_errors;
+
+       *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TSO);
+       *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANEX);
+       *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
+       *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
+       *data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
+       *data++ = s->rx_cong_drops;
+}
+
+static inline void reg_block_dump(struct adapter *ap, void *buf,
+                                 unsigned int start, unsigned int end)
+{
+       u32 *p = buf + start;
+
+       for (; start <= end; start += sizeof(u32))
+               *p++ = t3_read_reg(ap, start);
+}
+
+static void get_regs(struct net_device *dev, struct ethtool_regs *regs,
+                    void *buf)
+{
+       struct adapter *ap = dev->priv;
+
+       /*
+        * Version scheme:
+        * bits 0..9: chip version
+        * bits 10..15: chip revision
+        * bit 31: set for PCIe cards
+        */
+       regs->version = 3 | (ap->params.rev << 10) | (is_pcie(ap) << 31);
+
+       /*
+        * We skip the MAC statistics registers because they are clear-on-read.
+        * Also reading multi-register stats would need to synchronize with the
+        * periodic mac stats accumulation.  Hard to justify the complexity.
+        */
+       memset(buf, 0, T3_REGMAP_SIZE);
+       reg_block_dump(ap, buf, 0, A_SG_RSPQ_CREDIT_RETURN);
+       reg_block_dump(ap, buf, A_SG_HI_DRB_HI_THRSH, A_ULPRX_PBL_ULIMIT);
+       reg_block_dump(ap, buf, A_ULPTX_CONFIG, A_MPS_INT_CAUSE);
+       reg_block_dump(ap, buf, A_CPL_SWITCH_CNTRL, A_CPL_MAP_TBL_DATA);
+       reg_block_dump(ap, buf, A_SMB_GLOBAL_TIME_CFG, A_XGM_SERDES_STAT3);
+       reg_block_dump(ap, buf, A_XGM_SERDES_STATUS0,
+                      XGM_REG(A_XGM_SERDES_STAT3, 1));
+       reg_block_dump(ap, buf, XGM_REG(A_XGM_SERDES_STATUS0, 1),
+                      XGM_REG(A_XGM_RX_SPI4_SOP_EOP_CNT, 1));
+}
+
+static int restart_autoneg(struct net_device *dev)
+{
+       struct port_info *p = netdev_priv(dev);
+
+       if (!netif_running(dev))
+               return -EAGAIN;
+       if (p->link_config.autoneg != AUTONEG_ENABLE)
+               return -EINVAL;
+       p->phy.ops->autoneg_restart(&p->phy);
+       return 0;
+}
+
+static int cxgb3_phys_id(struct net_device *dev, u32 data)
+{
+       int i;
+       struct adapter *adapter = dev->priv;
+
+       if (data == 0)
+               data = 2;
+
+       for (i = 0; i < data * 2; i++) {
+               t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+                                (i & 1) ? F_GPIO0_OUT_VAL : 0);
+               if (msleep_interruptible(500))
+                       break;
+       }
+       t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+                        F_GPIO0_OUT_VAL);
+       return 0;
+}
+
+static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct port_info *p = netdev_priv(dev);
+
+       cmd->supported = p->link_config.supported;
+       cmd->advertising = p->link_config.advertising;
+
+       if (netif_carrier_ok(dev)) {
+               cmd->speed = p->link_config.speed;
+               cmd->duplex = p->link_config.duplex;
+       } else {
+               cmd->speed = -1;
+               cmd->duplex = -1;
+       }
+
+       cmd->port = (cmd->supported & SUPPORTED_TP) ? PORT_TP : PORT_FIBRE;
+       cmd->phy_address = p->phy.addr;
+       cmd->transceiver = XCVR_EXTERNAL;
+       cmd->autoneg = p->link_config.autoneg;
+       cmd->maxtxpkt = 0;
+       cmd->maxrxpkt = 0;
+       return 0;
+}
+
+static int speed_duplex_to_caps(int speed, int duplex)
+{
+       int cap = 0;
+
+       switch (speed) {
+       case SPEED_10:
+               if (duplex == DUPLEX_FULL)
+                       cap = SUPPORTED_10baseT_Full;
+               else
+                       cap = SUPPORTED_10baseT_Half;
+               break;
+       case SPEED_100:
+               if (duplex == DUPLEX_FULL)
+                       cap = SUPPORTED_100baseT_Full;
+               else
+                       cap = SUPPORTED_100baseT_Half;
+               break;
+       case SPEED_1000:
+               if (duplex == DUPLEX_FULL)
+                       cap = SUPPORTED_1000baseT_Full;
+               else
+                       cap = SUPPORTED_1000baseT_Half;
+               break;
+       case SPEED_10000:
+               if (duplex == DUPLEX_FULL)
+                       cap = SUPPORTED_10000baseT_Full;
+       }
+       return cap;
+}
+
+#define ADVERTISED_MASK (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
+                     ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
+                     ADVERTISED_1000baseT_Half | ADVERTISED_1000baseT_Full | \
+                     ADVERTISED_10000baseT_Full)
+
+static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct port_info *p = netdev_priv(dev);
+       struct link_config *lc = &p->link_config;
+
+       if (!(lc->supported & SUPPORTED_Autoneg))
+               return -EOPNOTSUPP;     /* can't change speed/duplex */
+
+       if (cmd->autoneg == AUTONEG_DISABLE) {
+               int cap = speed_duplex_to_caps(cmd->speed, cmd->duplex);
+
+               if (!(lc->supported & cap) || cmd->speed == SPEED_1000)
+                       return -EINVAL;
+               lc->requested_speed = cmd->speed;
+               lc->requested_duplex = cmd->duplex;
+               lc->advertising = 0;
+       } else {
+               cmd->advertising &= ADVERTISED_MASK;
+               cmd->advertising &= lc->supported;
+               if (!cmd->advertising)
+                       return -EINVAL;
+               lc->requested_speed = SPEED_INVALID;
+               lc->requested_duplex = DUPLEX_INVALID;
+               lc->advertising = cmd->advertising | ADVERTISED_Autoneg;
+       }
+       lc->autoneg = cmd->autoneg;
+       if (netif_running(dev))
+               t3_link_start(&p->phy, &p->mac, lc);
+       return 0;
+}
+
+static void get_pauseparam(struct net_device *dev,
+                          struct ethtool_pauseparam *epause)
+{
+       struct port_info *p = netdev_priv(dev);
+
+       epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0;
+       epause->rx_pause = (p->link_config.fc & PAUSE_RX) != 0;
+       epause->tx_pause = (p->link_config.fc & PAUSE_TX) != 0;
+}
+
+static int set_pauseparam(struct net_device *dev,
+                         struct ethtool_pauseparam *epause)
+{
+       struct port_info *p = netdev_priv(dev);
+       struct link_config *lc = &p->link_config;
+
+       if (epause->autoneg == AUTONEG_DISABLE)
+               lc->requested_fc = 0;
+       else if (lc->supported & SUPPORTED_Autoneg)
+               lc->requested_fc = PAUSE_AUTONEG;
+       else
+               return -EINVAL;
+
+       if (epause->rx_pause)
+               lc->requested_fc |= PAUSE_RX;
+       if (epause->tx_pause)
+               lc->requested_fc |= PAUSE_TX;
+       if (lc->autoneg == AUTONEG_ENABLE) {
+               if (netif_running(dev))
+                       t3_link_start(&p->phy, &p->mac, lc);
+       } else {
+               lc->fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+               if (netif_running(dev))
+                       t3_mac_set_speed_duplex_fc(&p->mac, -1, -1, lc->fc);
+       }
+       return 0;
+}
+
+static u32 get_rx_csum(struct net_device *dev)
+{
+       struct port_info *p = netdev_priv(dev);
+
+       return p->rx_csum_offload;
+}
+
+static int set_rx_csum(struct net_device *dev, u32 data)
+{
+       struct port_info *p = netdev_priv(dev);
+
+       p->rx_csum_offload = data;
+       return 0;
+}
+
+static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
+{
+       struct adapter *adapter = dev->priv;
+
+       e->rx_max_pending = MAX_RX_BUFFERS;
+       e->rx_mini_max_pending = 0;
+       e->rx_jumbo_max_pending = MAX_RX_JUMBO_BUFFERS;
+       e->tx_max_pending = MAX_TXQ_ENTRIES;
+
+       e->rx_pending = adapter->params.sge.qset[0].fl_size;
+       e->rx_mini_pending = adapter->params.sge.qset[0].rspq_size;
+       e->rx_jumbo_pending = adapter->params.sge.qset[0].jumbo_size;
+       e->tx_pending = adapter->params.sge.qset[0].txq_size[0];
+}
+
+static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e)
+{
+       int i;
+       struct adapter *adapter = dev->priv;
+
+       if (e->rx_pending > MAX_RX_BUFFERS ||
+           e->rx_jumbo_pending > MAX_RX_JUMBO_BUFFERS ||
+           e->tx_pending > MAX_TXQ_ENTRIES ||
+           e->rx_mini_pending > MAX_RSPQ_ENTRIES ||
+           e->rx_mini_pending < MIN_RSPQ_ENTRIES ||
+           e->rx_pending < MIN_FL_ENTRIES ||
+           e->rx_jumbo_pending < MIN_FL_ENTRIES ||
+           e->tx_pending < adapter->params.nports * MIN_TXQ_ENTRIES)
+               return -EINVAL;
+
+       if (adapter->flags & FULL_INIT_DONE)
+               return -EBUSY;
+
+       for (i = 0; i < SGE_QSETS; ++i) {
+               struct qset_params *q = &adapter->params.sge.qset[i];
+
+               q->rspq_size = e->rx_mini_pending;
+               q->fl_size = e->rx_pending;
+               q->jumbo_size = e->rx_jumbo_pending;
+               q->txq_size[0] = e->tx_pending;
+               q->txq_size[1] = e->tx_pending;
+               q->txq_size[2] = e->tx_pending;
+       }
+       return 0;
+}
+
+static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+{
+       struct adapter *adapter = dev->priv;
+       struct qset_params *qsp = &adapter->params.sge.qset[0];
+       struct sge_qset *qs = &adapter->sge.qs[0];
+
+       if (c->rx_coalesce_usecs * 10 > M_NEWTIMER)
+               return -EINVAL;
+
+       qsp->coalesce_usecs = c->rx_coalesce_usecs;
+       t3_update_qset_coalesce(qs, qsp);
+       return 0;
+}
+
+static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c)
+{
+       struct adapter *adapter = dev->priv;
+       struct qset_params *q = adapter->params.sge.qset;
+
+       c->rx_coalesce_usecs = q->coalesce_usecs;
+       return 0;
+}
+
+static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e,
+                     u8 * data)
+{
+       int i, err = 0;
+       struct adapter *adapter = dev->priv;
+
+       u8 *buf = kmalloc(EEPROMSIZE, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       e->magic = EEPROM_MAGIC;
+       for (i = e->offset & ~3; !err && i < e->offset + e->len; i += 4)
+               err = t3_seeprom_read(adapter, i, (u32 *) & buf[i]);
+
+       if (!err)
+               memcpy(data, buf + e->offset, e->len);
+       kfree(buf);
+       return err;
+}
+
+static int set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+                     u8 * data)
+{
+       u8 *buf;
+       int err = 0;
+       u32 aligned_offset, aligned_len, *p;
+       struct adapter *adapter = dev->priv;
+
+       if (eeprom->magic != EEPROM_MAGIC)
+               return -EINVAL;
+
+       aligned_offset = eeprom->offset & ~3;
+       aligned_len = (eeprom->len + (eeprom->offset & 3) + 3) & ~3;
+
+       if (aligned_offset != eeprom->offset || aligned_len != eeprom->len) {
+               buf = kmalloc(aligned_len, GFP_KERNEL);
+               if (!buf)
+                       return -ENOMEM;
+               err = t3_seeprom_read(adapter, aligned_offset, (u32 *) buf);
+               if (!err && aligned_len > 4)
+                       err = t3_seeprom_read(adapter,
+                                             aligned_offset + aligned_len - 4,
+                                             (u32 *) & buf[aligned_len - 4]);
+               if (err)
+                       goto out;
+               memcpy(buf + (eeprom->offset & 3), data, eeprom->len);
+       } else
+               buf = data;
+
+       err = t3_seeprom_wp(adapter, 0);
+       if (err)
+               goto out;
+
+       for (p = (u32 *) buf; !err && aligned_len; aligned_len -= 4, p++) {
+               err = t3_seeprom_write(adapter, aligned_offset, *p);
+               aligned_offset += 4;
+       }
+
+       if (!err)
+               err = t3_seeprom_wp(adapter, 1);
+out:
+       if (buf != data)
+               kfree(buf);
+       return err;
+}
+
+static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       wol->supported = 0;
+       wol->wolopts = 0;
+       memset(&wol->sopass, 0, sizeof(wol->sopass));
+}
+
+static const struct ethtool_ops cxgb_ethtool_ops = {
+       .get_settings = get_settings,
+       .set_settings = set_settings,
+       .get_drvinfo = get_drvinfo,
+       .get_msglevel = get_msglevel,
+       .set_msglevel = set_msglevel,
+       .get_ringparam = get_sge_param,
+       .set_ringparam = set_sge_param,
+       .get_coalesce = get_coalesce,
+       .set_coalesce = set_coalesce,
+       .get_eeprom_len = get_eeprom_len,
+       .get_eeprom = get_eeprom,
+       .set_eeprom = set_eeprom,
+       .get_pauseparam = get_pauseparam,
+       .set_pauseparam = set_pauseparam,
+       .get_rx_csum = get_rx_csum,
+       .set_rx_csum = set_rx_csum,
+       .get_tx_csum = ethtool_op_get_tx_csum,
+       .set_tx_csum = ethtool_op_set_tx_csum,
+       .get_sg = ethtool_op_get_sg,
+       .set_sg = ethtool_op_set_sg,
+       .get_link = ethtool_op_get_link,
+       .get_strings = get_strings,
+       .phys_id = cxgb3_phys_id,
+       .nway_reset = restart_autoneg,
+       .get_stats_count = get_stats_count,
+       .get_ethtool_stats = get_stats,
+       .get_regs_len = get_regs_len,
+       .get_regs = get_regs,
+       .get_wol = get_wol,
+       .get_tso = ethtool_op_get_tso,
+       .set_tso = ethtool_op_set_tso,
+       .get_perm_addr = ethtool_op_get_perm_addr
+};
+
+static int in_range(int val, int lo, int hi)
+{
+       return val < 0 || (val <= hi && val >= lo);
+}
+
+static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr)
+{
+       int ret;
+       u32 cmd;
+       struct adapter *adapter = dev->priv;
+
+       if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
+               return -EFAULT;
+
+       switch (cmd) {
+       case CHELSIO_SETREG:{
+               struct ch_reg edata;
+
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if (copy_from_user(&edata, useraddr, sizeof(edata)))
+                       return -EFAULT;
+               if ((edata.addr & 3) != 0
+                       || edata.addr >= adapter->mmio_len)
+                       return -EINVAL;
+               writel(edata.val, adapter->regs + edata.addr);
+               break;
+       }
+       case CHELSIO_GETREG:{
+               struct ch_reg edata;
+
+               if (copy_from_user(&edata, useraddr, sizeof(edata)))
+                       return -EFAULT;
+               if ((edata.addr & 3) != 0
+                       || edata.addr >= adapter->mmio_len)
+                       return -EINVAL;
+               edata.val = readl(adapter->regs + edata.addr);
+               if (copy_to_user(useraddr, &edata, sizeof(edata)))
+                       return -EFAULT;
+               break;
+       }
+       case CHELSIO_SET_QSET_PARAMS:{
+               int i;
+               struct qset_params *q;
+               struct ch_qset_params t;
+
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if (copy_from_user(&t, useraddr, sizeof(t)))
+                       return -EFAULT;
+               if (t.qset_idx >= SGE_QSETS)
+                       return -EINVAL;
+               if (!in_range(t.intr_lat, 0, M_NEWTIMER) ||
+                       !in_range(t.cong_thres, 0, 255) ||
+                       !in_range(t.txq_size[0], MIN_TXQ_ENTRIES,
+                               MAX_TXQ_ENTRIES) ||
+                       !in_range(t.txq_size[1], MIN_TXQ_ENTRIES,
+                               MAX_TXQ_ENTRIES) ||
+                       !in_range(t.txq_size[2], MIN_CTRL_TXQ_ENTRIES,
+                               MAX_CTRL_TXQ_ENTRIES) ||
+                       !in_range(t.fl_size[0], MIN_FL_ENTRIES,
+                               MAX_RX_BUFFERS)
+                       || !in_range(t.fl_size[1], MIN_FL_ENTRIES,
+                                       MAX_RX_JUMBO_BUFFERS)
+                       || !in_range(t.rspq_size, MIN_RSPQ_ENTRIES,
+                                       MAX_RSPQ_ENTRIES))
+                       return -EINVAL;
+               if ((adapter->flags & FULL_INIT_DONE) &&
+                       (t.rspq_size >= 0 || t.fl_size[0] >= 0 ||
+                       t.fl_size[1] >= 0 || t.txq_size[0] >= 0 ||
+                       t.txq_size[1] >= 0 || t.txq_size[2] >= 0 ||
+                       t.polling >= 0 || t.cong_thres >= 0))
+                       return -EBUSY;
+
+               q = &adapter->params.sge.qset[t.qset_idx];
+
+               if (t.rspq_size >= 0)
+                       q->rspq_size = t.rspq_size;
+               if (t.fl_size[0] >= 0)
+                       q->fl_size = t.fl_size[0];
+               if (t.fl_size[1] >= 0)
+                       q->jumbo_size = t.fl_size[1];
+               if (t.txq_size[0] >= 0)
+                       q->txq_size[0] = t.txq_size[0];
+               if (t.txq_size[1] >= 0)
+                       q->txq_size[1] = t.txq_size[1];
+               if (t.txq_size[2] >= 0)
+                       q->txq_size[2] = t.txq_size[2];
+               if (t.cong_thres >= 0)
+                       q->cong_thres = t.cong_thres;
+               if (t.intr_lat >= 0) {
+                       struct sge_qset *qs =
+                               &adapter->sge.qs[t.qset_idx];
+
+                       q->coalesce_usecs = t.intr_lat;
+                       t3_update_qset_coalesce(qs, q);
+               }
+               if (t.polling >= 0) {
+                       if (adapter->flags & USING_MSIX)
+                               q->polling = t.polling;
+                       else {
+                               /* No polling with INTx for T3A */
+                               if (adapter->params.rev == 0 &&
+                                       !(adapter->flags & USING_MSI))
+                                       t.polling = 0;
+
+                               for (i = 0; i < SGE_QSETS; i++) {
+                                       q = &adapter->params.sge.
+                                               qset[i];
+                                       q->polling = t.polling;
+                               }
+                       }
+               }
+               break;
+       }
+       case CHELSIO_GET_QSET_PARAMS:{
+               struct qset_params *q;
+               struct ch_qset_params t;
+
+               if (copy_from_user(&t, useraddr, sizeof(t)))
+                       return -EFAULT;
+               if (t.qset_idx >= SGE_QSETS)
+                       return -EINVAL;
+
+               q = &adapter->params.sge.qset[t.qset_idx];
+               t.rspq_size = q->rspq_size;
+               t.txq_size[0] = q->txq_size[0];
+               t.txq_size[1] = q->txq_size[1];
+               t.txq_size[2] = q->txq_size[2];
+               t.fl_size[0] = q->fl_size;
+               t.fl_size[1] = q->jumbo_size;
+               t.polling = q->polling;
+               t.intr_lat = q->coalesce_usecs;
+               t.cong_thres = q->cong_thres;
+
+               if (copy_to_user(useraddr, &t, sizeof(t)))
+                       return -EFAULT;
+               break;
+       }
+       case CHELSIO_SET_QSET_NUM:{
+               struct ch_reg edata;
+               struct port_info *pi = netdev_priv(dev);
+               unsigned int i, first_qset = 0, other_qsets = 0;
+
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if (adapter->flags & FULL_INIT_DONE)
+                       return -EBUSY;
+               if (copy_from_user(&edata, useraddr, sizeof(edata)))
+                       return -EFAULT;
+               if (edata.val < 1 ||
+                       (edata.val > 1 && !(adapter->flags & USING_MSIX)))
+                       return -EINVAL;
+
+               for_each_port(adapter, i)
+                       if (adapter->port[i] && adapter->port[i] != dev)
+                               other_qsets += adap2pinfo(adapter, i)->nqsets;
+
+               if (edata.val + other_qsets > SGE_QSETS)
+                       return -EINVAL;
+
+               pi->nqsets = edata.val;
+
+               for_each_port(adapter, i)
+                       if (adapter->port[i]) {
+                               pi = adap2pinfo(adapter, i);
+                               pi->first_qset = first_qset;
+                               first_qset += pi->nqsets;
+                       }
+               break;
+       }
+       case CHELSIO_GET_QSET_NUM:{
+               struct ch_reg edata;
+               struct port_info *pi = netdev_priv(dev);
+
+               edata.cmd = CHELSIO_GET_QSET_NUM;
+               edata.val = pi->nqsets;
+               if (copy_to_user(useraddr, &edata, sizeof(edata)))
+                       return -EFAULT;
+               break;
+       }
+       case CHELSIO_LOAD_FW:{
+               u8 *fw_data;
+               struct ch_mem_range t;
+
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if (copy_from_user(&t, useraddr, sizeof(t)))
+                       return -EFAULT;
+
+               fw_data = kmalloc(t.len, GFP_KERNEL);
+               if (!fw_data)
+                       return -ENOMEM;
+
+               if (copy_from_user
+                       (fw_data, useraddr + sizeof(t), t.len)) {
+                       kfree(fw_data);
+                       return -EFAULT;
+               }
+
+               ret = t3_load_fw(adapter, fw_data, t.len);
+               kfree(fw_data);
+               if (ret)
+                       return ret;
+               break;
+       }
+       case CHELSIO_SETMTUTAB:{
+               struct ch_mtus m;
+               int i;
+
+               if (!is_offload(adapter))
+                       return -EOPNOTSUPP;
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if (offload_running(adapter))
+                       return -EBUSY;
+               if (copy_from_user(&m, useraddr, sizeof(m)))
+                       return -EFAULT;
+               if (m.nmtus != NMTUS)
+                       return -EINVAL;
+               if (m.mtus[0] < 81)     /* accommodate SACK */
+                       return -EINVAL;
+
+               /* MTUs must be in ascending order */
+               for (i = 1; i < NMTUS; ++i)
+                       if (m.mtus[i] < m.mtus[i - 1])
+                               return -EINVAL;
+
+               memcpy(adapter->params.mtus, m.mtus,
+                       sizeof(adapter->params.mtus));
+               break;
+       }
+       case CHELSIO_GET_PM:{
+               struct tp_params *p = &adapter->params.tp;
+               struct ch_pm m = {.cmd = CHELSIO_GET_PM };
+
+               if (!is_offload(adapter))
+                       return -EOPNOTSUPP;
+               m.tx_pg_sz = p->tx_pg_size;
+               m.tx_num_pg = p->tx_num_pgs;
+               m.rx_pg_sz = p->rx_pg_size;
+               m.rx_num_pg = p->rx_num_pgs;
+               m.pm_total = p->pmtx_size + p->chan_rx_size * p->nchan;
+               if (copy_to_user(useraddr, &m, sizeof(m)))
+                       return -EFAULT;
+               break;
+       }
+       case CHELSIO_SET_PM:{
+               struct ch_pm m;
+               struct tp_params *p = &adapter->params.tp;
+
+               if (!is_offload(adapter))
+                       return -EOPNOTSUPP;
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if (adapter->flags & FULL_INIT_DONE)
+                       return -EBUSY;
+               if (copy_from_user(&m, useraddr, sizeof(m)))
+                       return -EFAULT;
+               if (!m.rx_pg_sz || (m.rx_pg_sz & (m.rx_pg_sz - 1)) ||
+                       !m.tx_pg_sz || (m.tx_pg_sz & (m.tx_pg_sz - 1)))
+                       return -EINVAL; /* not power of 2 */
+               if (!(m.rx_pg_sz & 0x14000))
+                       return -EINVAL; /* not 16KB or 64KB */
+               if (!(m.tx_pg_sz & 0x1554000))
+                       return -EINVAL;
+               if (m.tx_num_pg == -1)
+                       m.tx_num_pg = p->tx_num_pgs;
+               if (m.rx_num_pg == -1)
+                       m.rx_num_pg = p->rx_num_pgs;
+               if (m.tx_num_pg % 24 || m.rx_num_pg % 24)
+                       return -EINVAL;
+               if (m.rx_num_pg * m.rx_pg_sz > p->chan_rx_size ||
+                       m.tx_num_pg * m.tx_pg_sz > p->chan_tx_size)
+                       return -EINVAL;
+               p->rx_pg_size = m.rx_pg_sz;
+               p->tx_pg_size = m.tx_pg_sz;
+               p->rx_num_pgs = m.rx_num_pg;
+               p->tx_num_pgs = m.tx_num_pg;
+               break;
+       }
+       case CHELSIO_GET_MEM:{
+               struct ch_mem_range t;
+               struct mc7 *mem;
+               u64 buf[32];
+
+               if (!is_offload(adapter))
+                       return -EOPNOTSUPP;
+               if (!(adapter->flags & FULL_INIT_DONE))
+                       return -EIO;    /* need the memory controllers */
+               if (copy_from_user(&t, useraddr, sizeof(t)))
+                       return -EFAULT;
+               if ((t.addr & 7) || (t.len & 7))
+                       return -EINVAL;
+               if (t.mem_id == MEM_CM)
+                       mem = &adapter->cm;
+               else if (t.mem_id == MEM_PMRX)
+                       mem = &adapter->pmrx;
+               else if (t.mem_id == MEM_PMTX)
+                       mem = &adapter->pmtx;
+               else
+                       return -EINVAL;
+
+               /*
+                       * Version scheme:
+                       * bits 0..9: chip version
+                       * bits 10..15: chip revision
+                       */
+               t.version = 3 | (adapter->params.rev << 10);
+               if (copy_to_user(useraddr, &t, sizeof(t)))
+                       return -EFAULT;
+
+               /*
+                * Read 256 bytes at a time as len can be large and we don't
+                * want to use huge intermediate buffers.
+                */
+               useraddr += sizeof(t);  /* advance to start of buffer */
+               while (t.len) {
+                       unsigned int chunk =
+                               min_t(unsigned int, t.len, sizeof(buf));
+
+                       ret =
+                               t3_mc7_bd_read(mem, t.addr / 8, chunk / 8,
+                                               buf);
+                       if (ret)
+                               return ret;
+                       if (copy_to_user(useraddr, buf, chunk))
+                               return -EFAULT;
+                       useraddr += chunk;
+                       t.addr += chunk;
+                       t.len -= chunk;
+               }
+               break;
+       }
+       case CHELSIO_SET_TRACE_FILTER:{
+               struct ch_trace t;
+               const struct trace_params *tp;
+
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if (!offload_running(adapter))
+                       return -EAGAIN;
+               if (copy_from_user(&t, useraddr, sizeof(t)))
+                       return -EFAULT;
+
+               tp = (const struct trace_params *)&t.sip;
+               if (t.config_tx)
+                       t3_config_trace_filter(adapter, tp, 0,
+                                               t.invert_match,
+                                               t.trace_tx);
+               if (t.config_rx)
+                       t3_config_trace_filter(adapter, tp, 1,
+                                               t.invert_match,
+                                               t.trace_rx);
+               break;
+       }
+       case CHELSIO_SET_PKTSCHED:{
+               struct ch_pktsched_params p;
+
+               if (!capable(CAP_NET_ADMIN))
+                               return -EPERM;
+               if (!adapter->open_device_map)
+                               return -EAGAIN; /* uP and SGE must be running */
+               if (copy_from_user(&p, useraddr, sizeof(p)))
+                               return -EFAULT;
+               send_pktsched_cmd(adapter, p.sched, p.idx, p.min, p.max,
+                                 p.binding);
+               break;
+                       
+       }
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+static int cxgb_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
+{
+       int ret, mmd;
+       struct adapter *adapter = dev->priv;
+       struct port_info *pi = netdev_priv(dev);
+       struct mii_ioctl_data *data = if_mii(req);
+
+       switch (cmd) {
+       case SIOCGMIIPHY:
+               data->phy_id = pi->phy.addr;
+               /* FALLTHRU */
+       case SIOCGMIIREG:{
+               u32 val;
+               struct cphy *phy = &pi->phy;
+
+               if (!phy->mdio_read)
+                       return -EOPNOTSUPP;
+               if (is_10G(adapter)) {
+                       mmd = data->phy_id >> 8;
+                       if (!mmd)
+                               mmd = MDIO_DEV_PCS;
+                       else if (mmd > MDIO_DEV_XGXS)
+                               return -EINVAL;
+
+                       ret =
+                               phy->mdio_read(adapter, data->phy_id & 0x1f,
+                                               mmd, data->reg_num, &val);
+               } else
+                       ret =
+                               phy->mdio_read(adapter, data->phy_id & 0x1f,
+                                               0, data->reg_num & 0x1f,
+                                               &val);
+               if (!ret)
+                       data->val_out = val;
+               break;
+       }
+       case SIOCSMIIREG:{
+               struct cphy *phy = &pi->phy;
+
+               if (!capable(CAP_NET_ADMIN))
+                       return -EPERM;
+               if (!phy->mdio_write)
+                       return -EOPNOTSUPP;
+               if (is_10G(adapter)) {
+                       mmd = data->phy_id >> 8;
+                       if (!mmd)
+                               mmd = MDIO_DEV_PCS;
+                       else if (mmd > MDIO_DEV_XGXS)
+                               return -EINVAL;
+
+                       ret =
+                               phy->mdio_write(adapter,
+                                               data->phy_id & 0x1f, mmd,
+                                               data->reg_num,
+                                               data->val_in);
+               } else
+                       ret =
+                               phy->mdio_write(adapter,
+                                               data->phy_id & 0x1f, 0,
+                                               data->reg_num & 0x1f,
+                                               data->val_in);
+               break;
+       }
+       case SIOCCHIOCTL:
+               return cxgb_extension_ioctl(dev, req->ifr_data);
+       default:
+               return -EOPNOTSUPP;
+       }
+       return ret;
+}
+
+static int cxgb_change_mtu(struct net_device *dev, int new_mtu)
+{
+       int ret;
+       struct adapter *adapter = dev->priv;
+       struct port_info *pi = netdev_priv(dev);
+
+       if (new_mtu < 81)       /* accommodate SACK */
+               return -EINVAL;
+       if ((ret = t3_mac_set_mtu(&pi->mac, new_mtu)))
+               return ret;
+       dev->mtu = new_mtu;
+       init_port_mtus(adapter);
+       if (adapter->params.rev == 0 && offload_running(adapter))
+               t3_load_mtus(adapter, adapter->params.mtus,
+                            adapter->params.a_wnd, adapter->params.b_wnd,
+                            adapter->port[0]->mtu);
+       return 0;
+}
+
+static int cxgb_set_mac_addr(struct net_device *dev, void *p)
+{
+       struct adapter *adapter = dev->priv;
+       struct port_info *pi = netdev_priv(dev);
+       struct sockaddr *addr = p;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EINVAL;
+
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+       t3_mac_set_address(&pi->mac, 0, dev->dev_addr);
+       if (offload_running(adapter))
+               write_smt_entry(adapter, pi->port_id);
+       return 0;
+}
+
+/**
+ * t3_synchronize_rx - wait for current Rx processing on a port to complete
+ * @adap: the adapter
+ * @p: the port
+ *
+ * Ensures that current Rx processing on any of the queues associated with
+ * the given port completes before returning.  We do this by acquiring and
+ * releasing the locks of the response queues associated with the port.
+ */
+static void t3_synchronize_rx(struct adapter *adap, const struct port_info *p)
+{
+       int i;
+
+       for (i = 0; i < p->nqsets; i++) {
+               struct sge_rspq *q = &adap->sge.qs[i + p->first_qset].rspq;
+
+               spin_lock_irq(&q->lock);
+               spin_unlock_irq(&q->lock);
+       }
+}
+
+static void vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
+{
+       struct adapter *adapter = dev->priv;
+       struct port_info *pi = netdev_priv(dev);
+
+       pi->vlan_grp = grp;
+       if (adapter->params.rev > 0)
+               t3_set_vlan_accel(adapter, 1 << pi->port_id, grp != NULL);
+       else {
+               /* single control for all ports */
+               unsigned int i, have_vlans = 0;
+               for_each_port(adapter, i)
+                   have_vlans |= adap2pinfo(adapter, i)->vlan_grp != NULL;
+
+               t3_set_vlan_accel(adapter, 1, have_vlans);
+       }
+       t3_synchronize_rx(adapter, pi);
+}
+
+static void vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+       /* nothing */
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void cxgb_netpoll(struct net_device *dev)
+{
+       struct adapter *adapter = dev->priv;
+       struct sge_qset *qs = dev2qset(dev);
+
+       t3_intr_handler(adapter, qs->rspq.polling) (adapter->pdev->irq,
+                                                   adapter);
+}
+#endif
+
+/*
+ * Periodic accumulation of MAC statistics.
+ */
+static void mac_stats_update(struct adapter *adapter)
+{
+       int i;
+
+       for_each_port(adapter, i) {
+               struct net_device *dev = adapter->port[i];
+               struct port_info *p = netdev_priv(dev);
+
+               if (netif_running(dev)) {
+                       spin_lock(&adapter->stats_lock);
+                       t3_mac_update_stats(&p->mac);
+                       spin_unlock(&adapter->stats_lock);
+               }
+       }
+}
+
+static void check_link_status(struct adapter *adapter)
+{
+       int i;
+
+       for_each_port(adapter, i) {
+               struct net_device *dev = adapter->port[i];
+               struct port_info *p = netdev_priv(dev);
+
+               if (!(p->port_type->caps & SUPPORTED_IRQ) && netif_running(dev))
+                       t3_link_changed(adapter, i);
+       }
+}
+
+static void t3_adap_check_task(struct work_struct *work)
+{
+       struct adapter *adapter = container_of(work, struct adapter,
+                                              adap_check_task.work);
+       const struct adapter_params *p = &adapter->params;
+
+       adapter->check_task_cnt++;
+
+       /* Check link status for PHYs without interrupts */
+       if (p->linkpoll_period)
+               check_link_status(adapter);
+
+       /* Accumulate MAC stats if needed */
+       if (!p->linkpoll_period ||
+           (adapter->check_task_cnt * p->linkpoll_period) / 10 >=
+           p->stats_update_period) {
+               mac_stats_update(adapter);
+               adapter->check_task_cnt = 0;
+       }
+
+       /* Schedule the next check update if any port is active. */
+       spin_lock(&adapter->work_lock);
+       if (adapter->open_device_map & PORT_MASK)
+               schedule_chk_task(adapter);
+       spin_unlock(&adapter->work_lock);
+}
+
+/*
+ * Processes external (PHY) interrupts in process context.
+ */
+static void ext_intr_task(struct work_struct *work)
+{
+       struct adapter *adapter = container_of(work, struct adapter,
+                                              ext_intr_handler_task);
+
+       t3_phy_intr_handler(adapter);
+
+       /* Now reenable external interrupts */
+       spin_lock_irq(&adapter->work_lock);
+       if (adapter->slow_intr_mask) {
+               adapter->slow_intr_mask |= F_T3DBG;
+               t3_write_reg(adapter, A_PL_INT_CAUSE0, F_T3DBG);
+               t3_write_reg(adapter, A_PL_INT_ENABLE0,
+                            adapter->slow_intr_mask);
+       }
+       spin_unlock_irq(&adapter->work_lock);
+}
+
+/*
+ * Interrupt-context handler for external (PHY) interrupts.
+ */
+void t3_os_ext_intr_handler(struct adapter *adapter)
+{
+       /*
+        * Schedule a task to handle external interrupts as they may be slow
+        * and we use a mutex to protect MDIO registers.  We disable PHY
+        * interrupts in the meantime and let the task reenable them when
+        * it's done.
+        */
+       spin_lock(&adapter->work_lock);
+       if (adapter->slow_intr_mask) {
+               adapter->slow_intr_mask &= ~F_T3DBG;
+               t3_write_reg(adapter, A_PL_INT_ENABLE0,
+                            adapter->slow_intr_mask);
+               queue_work(cxgb3_wq, &adapter->ext_intr_handler_task);
+       }
+       spin_unlock(&adapter->work_lock);
+}
+
+void t3_fatal_err(struct adapter *adapter)
+{
+       unsigned int fw_status[4];
+
+       if (adapter->flags & FULL_INIT_DONE) {
+               t3_sge_stop(adapter);
+               t3_intr_disable(adapter);
+       }
+       CH_ALERT(adapter, "encountered fatal error, operation suspended\n");
+       if (!t3_cim_ctl_blk_read(adapter, 0xa0, 4, fw_status))
+               CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
+                        fw_status[0], fw_status[1],
+                        fw_status[2], fw_status[3]);
+
+}
+
+static int __devinit cxgb_enable_msix(struct adapter *adap)
+{
+       struct msix_entry entries[SGE_QSETS + 1];
+       int i, err;
+
+       for (i = 0; i < ARRAY_SIZE(entries); ++i)
+               entries[i].entry = i;
+
+       err = pci_enable_msix(adap->pdev, entries, ARRAY_SIZE(entries));
+       if (!err) {
+               for (i = 0; i < ARRAY_SIZE(entries); ++i)
+                       adap->msix_info[i].vec = entries[i].vector;
+       } else if (err > 0)
+               dev_info(&adap->pdev->dev,
+                      "only %d MSI-X vectors left, not using MSI-X\n", err);
+       return err;
+}
+
+static void __devinit print_port_info(struct adapter *adap,
+                                     const struct adapter_info *ai)
+{
+       static const char *pci_variant[] = {
+               "PCI", "PCI-X", "PCI-X ECC", "PCI-X 266", "PCI Express"
+       };
+
+       int i;
+       char buf[80];
+
+       if (is_pcie(adap))
+               snprintf(buf, sizeof(buf), "%s x%d",
+                        pci_variant[adap->params.pci.variant],
+                        adap->params.pci.width);
+       else
+               snprintf(buf, sizeof(buf), "%s %dMHz/%d-bit",
+                        pci_variant[adap->params.pci.variant],
+                        adap->params.pci.speed, adap->params.pci.width);
+
+       for_each_port(adap, i) {
+               struct net_device *dev = adap->port[i];
+               const struct port_info *pi = netdev_priv(dev);
+
+               if (!test_bit(i, &adap->registered_device_map))
+                       continue;
+               printk(KERN_INFO "%s: %s %s RNIC (rev %d) %s%s\n",
+                      dev->name, ai->desc, pi->port_type->desc,
+                      adap->params.rev, buf,
+                      (adap->flags & USING_MSIX) ? " MSI-X" :
+                      (adap->flags & USING_MSI) ? " MSI" : "");
+               if (adap->name == dev->name && adap->params.vpd.mclk)
+                       printk(KERN_INFO "%s: %uMB CM, %uMB PMTX, %uMB PMRX\n",
+                              adap->name, t3_mc7_size(&adap->cm) >> 20,
+                              t3_mc7_size(&adap->pmtx) >> 20,
+                              t3_mc7_size(&adap->pmrx) >> 20);
+       }
+}
+
+static int __devinit init_one(struct pci_dev *pdev,
+                             const struct pci_device_id *ent)
+{
+       static int version_printed;
+
+       int i, err, pci_using_dac = 0;
+       unsigned long mmio_start, mmio_len;
+       const struct adapter_info *ai;
+       struct adapter *adapter = NULL;
+       struct port_info *pi;
+
+       if (!version_printed) {
+               printk(KERN_INFO "%s - version %s\n", DRV_DESC, DRV_VERSION);
+               ++version_printed;
+       }
+
+       if (!cxgb3_wq) {
+               cxgb3_wq = create_singlethread_workqueue(DRV_NAME);
+               if (!cxgb3_wq) {
+                       printk(KERN_ERR DRV_NAME
+                              ": cannot initialize work queue\n");
+                       return -ENOMEM;
+               }
+       }
+
+       err = pci_request_regions(pdev, DRV_NAME);
+       if (err) {
+               /* Just info, some other driver may have claimed the device. */
+               dev_info(&pdev->dev, "cannot obtain PCI resources\n");
+               return err;
+       }
+
+       err = pci_enable_device(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "cannot enable PCI device\n");
+               goto out_release_regions;
+       }
+
+       if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+               pci_using_dac = 1;
+               err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+               if (err) {
+                       dev_err(&pdev->dev, "unable to obtain 64-bit DMA for "
+                              "coherent allocations\n");
+                       goto out_disable_device;
+               }
+       } else if ((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
+               dev_err(&pdev->dev, "no usable DMA configuration\n");
+               goto out_disable_device;
+       }
+
+       pci_set_master(pdev);
+
+       mmio_start = pci_resource_start(pdev, 0);
+       mmio_len = pci_resource_len(pdev, 0);
+       ai = t3_get_adapter_info(ent->driver_data);
+
+       adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
+       if (!adapter) {
+               err = -ENOMEM;
+               goto out_disable_device;
+       }
+
+       adapter->regs = ioremap_nocache(mmio_start, mmio_len);
+       if (!adapter->regs) {
+               dev_err(&pdev->dev, "cannot map device registers\n");
+               err = -ENOMEM;
+               goto out_free_adapter;
+       }
+
+       adapter->pdev = pdev;
+       adapter->name = pci_name(pdev);
+       adapter->msg_enable = dflt_msg_enable;
+       adapter->mmio_len = mmio_len;
+
+       mutex_init(&adapter->mdio_lock);
+       spin_lock_init(&adapter->work_lock);
+       spin_lock_init(&adapter->stats_lock);
+
+       INIT_LIST_HEAD(&adapter->adapter_list);
+       INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
+       INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
+
+       for (i = 0; i < ai->nports; ++i) {
+               struct net_device *netdev;
+
+               netdev = alloc_etherdev(sizeof(struct port_info));
+               if (!netdev) {
+                       err = -ENOMEM;
+                       goto out_free_dev;
+               }
+
+               SET_MODULE_OWNER(netdev);
+               SET_NETDEV_DEV(netdev, &pdev->dev);
+
+               adapter->port[i] = netdev;
+               pi = netdev_priv(netdev);
+               pi->rx_csum_offload = 1;
+               pi->nqsets = 1;
+               pi->first_qset = i;
+               pi->activity = 0;
+               pi->port_id = i;
+               netif_carrier_off(netdev);
+               netdev->irq = pdev->irq;
+               netdev->mem_start = mmio_start;
+               netdev->mem_end = mmio_start + mmio_len - 1;
+               netdev->priv = adapter;
+               netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
+               netdev->features |= NETIF_F_LLTX;
+               if (pci_using_dac)
+                       netdev->features |= NETIF_F_HIGHDMA;
+
+               netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+               netdev->vlan_rx_register = vlan_rx_register;
+               netdev->vlan_rx_kill_vid = vlan_rx_kill_vid;
+
+               netdev->open = cxgb_open;
+               netdev->stop = cxgb_close;
+               netdev->hard_start_xmit = t3_eth_xmit;
+               netdev->get_stats = cxgb_get_stats;
+               netdev->set_multicast_list = cxgb_set_rxmode;
+               netdev->do_ioctl = cxgb_ioctl;
+               netdev->change_mtu = cxgb_change_mtu;
+               netdev->set_mac_address = cxgb_set_mac_addr;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+               netdev->poll_controller = cxgb_netpoll;
+#endif
+               netdev->weight = 64;
+
+               SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops);
+       }
+
+       pci_set_drvdata(pdev, adapter->port[0]);
+       if (t3_prep_adapter(adapter, ai, 1) < 0) {
+               err = -ENODEV;
+               goto out_free_dev;
+       }
+
+       /*
+        * The card is now ready to go.  If any errors occur during device
+        * registration we do not fail the whole card but rather proceed only
+        * with the ports we manage to register successfully.  However we must
+        * register at least one net device.
+        */
+       for_each_port(adapter, i) {
+               err = register_netdev(adapter->port[i]);
+               if (err)
+                       dev_warn(&pdev->dev,
+                                "cannot register net device %s, skipping\n",
+                                adapter->port[i]->name);
+               else {
+                       /*
+                        * Change the name we use for messages to the name of
+                        * the first successfully registered interface.
+                        */
+                       if (!adapter->registered_device_map)
+                               adapter->name = adapter->port[i]->name;
+
+                       __set_bit(i, &adapter->registered_device_map);
+               }
+       }
+       if (!adapter->registered_device_map) {
+               dev_err(&pdev->dev, "could not register any net devices\n");
+               goto out_free_dev;
+       }
+
+       /* Driver's ready. Reflect it on LEDs */
+       t3_led_ready(adapter);
+
+       if (is_offload(adapter)) {
+               __set_bit(OFFLOAD_DEVMAP_BIT, &adapter->registered_device_map);
+               cxgb3_adapter_ofld(adapter);
+       }
+
+       /* See what interrupts we'll be using */
+       if (msi > 1 && cxgb_enable_msix(adapter) == 0)
+               adapter->flags |= USING_MSIX;
+       else if (msi > 0 && pci_enable_msi(pdev) == 0)
+               adapter->flags |= USING_MSI;
+
+       err = sysfs_create_group(&adapter->port[0]->class_dev.kobj,
+                                &cxgb3_attr_group);
+
+       print_port_info(adapter, ai);
+       return 0;
+
+out_free_dev:
+       iounmap(adapter->regs);
+       for (i = ai->nports - 1; i >= 0; --i)
+               if (adapter->port[i])
+                       free_netdev(adapter->port[i]);
+
+out_free_adapter:
+       kfree(adapter);
+
+out_disable_device:
+       pci_disable_device(pdev);
+out_release_regions:
+       pci_release_regions(pdev);
+       pci_set_drvdata(pdev, NULL);
+       return err;
+}
+
+static void __devexit remove_one(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+
+       if (dev) {
+               int i;
+               struct adapter *adapter = dev->priv;
+
+               t3_sge_stop(adapter);
+               sysfs_remove_group(&adapter->port[0]->class_dev.kobj,
+                                  &cxgb3_attr_group);
+
+               for_each_port(adapter, i)
+                   if (test_bit(i, &adapter->registered_device_map))
+                       unregister_netdev(adapter->port[i]);
+
+               if (is_offload(adapter)) {
+                       cxgb3_adapter_unofld(adapter);
+                       if (test_bit(OFFLOAD_DEVMAP_BIT,
+                                    &adapter->open_device_map))
+                               offload_close(&adapter->tdev);
+               }
+
+               t3_free_sge_resources(adapter);
+               cxgb_disable_msi(adapter);
+
+               for (i = 0; i < ARRAY_SIZE(adapter->dummy_netdev); i++)
+                       if (adapter->dummy_netdev[i]) {
+                               free_netdev(adapter->dummy_netdev[i]);
+                               adapter->dummy_netdev[i] = NULL;
+                       }
+
+               for_each_port(adapter, i)
+                       if (adapter->port[i])
+                               free_netdev(adapter->port[i]);
+
+               iounmap(adapter->regs);
+               kfree(adapter);
+               pci_release_regions(pdev);
+               pci_disable_device(pdev);
+               pci_set_drvdata(pdev, NULL);
+       }
+}
+
+static struct pci_driver driver = {
+       .name = DRV_NAME,
+       .id_table = cxgb3_pci_tbl,
+       .probe = init_one,
+       .remove = __devexit_p(remove_one),
+};
+
+static int __init cxgb3_init_module(void)
+{
+       int ret;
+
+       cxgb3_offload_init();
+
+       ret = pci_register_driver(&driver);
+       return ret;
+}
+
+static void __exit cxgb3_cleanup_module(void)
+{
+       pci_unregister_driver(&driver);
+       if (cxgb3_wq)
+               destroy_workqueue(cxgb3_wq);
+}
+
+module_init(cxgb3_init_module);
+module_exit(cxgb3_cleanup_module);
diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c
new file mode 100644 (file)
index 0000000..c3a02d6
--- /dev/null
@@ -0,0 +1,1222 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/list.h>
+#include <net/neighbour.h>
+#include <linux/notifier.h>
+#include <asm/atomic.h>
+#include <linux/proc_fs.h>
+#include <linux/if_vlan.h>
+#include <net/netevent.h>
+#include <linux/highmem.h>
+#include <linux/vmalloc.h>
+
+#include "common.h"
+#include "regs.h"
+#include "cxgb3_ioctl.h"
+#include "cxgb3_ctl_defs.h"
+#include "cxgb3_defs.h"
+#include "l2t.h"
+#include "firmware_exports.h"
+#include "cxgb3_offload.h"
+
+static LIST_HEAD(client_list);
+static LIST_HEAD(ofld_dev_list);
+static DEFINE_MUTEX(cxgb3_db_lock);
+
+static DEFINE_RWLOCK(adapter_list_lock);
+static LIST_HEAD(adapter_list);
+
+static const unsigned int MAX_ATIDS = 64 * 1024;
+static const unsigned int ATID_BASE = 0x100000;
+
+static inline int offload_activated(struct t3cdev *tdev)
+{
+       const struct adapter *adapter = tdev2adap(tdev);
+
+       return (test_bit(OFFLOAD_DEVMAP_BIT, &adapter->open_device_map));
+}
+
+/**
+ *     cxgb3_register_client - register an offload client
+ *     @client: the client
+ *
+ *     Add the client to the client list,
+ *     and call backs the client for each activated offload device
+ */
+void cxgb3_register_client(struct cxgb3_client *client)
+{
+       struct t3cdev *tdev;
+
+       mutex_lock(&cxgb3_db_lock);
+       list_add_tail(&client->client_list, &client_list);
+
+       if (client->add) {
+               list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
+                       if (offload_activated(tdev))
+                               client->add(tdev);
+               }
+       }
+       mutex_unlock(&cxgb3_db_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_register_client);
+
+/**
+ *     cxgb3_unregister_client - unregister an offload client
+ *     @client: the client
+ *
+ *     Remove the client to the client list,
+ *     and call backs the client for each activated offload device.
+ */
+void cxgb3_unregister_client(struct cxgb3_client *client)
+{
+       struct t3cdev *tdev;
+
+       mutex_lock(&cxgb3_db_lock);
+       list_del(&client->client_list);
+
+       if (client->remove) {
+               list_for_each_entry(tdev, &ofld_dev_list, ofld_dev_list) {
+                       if (offload_activated(tdev))
+                               client->remove(tdev);
+               }
+       }
+       mutex_unlock(&cxgb3_db_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_unregister_client);
+
+/**
+ *     cxgb3_add_clients - activate registered clients for an offload device
+ *     @tdev: the offload device
+ *
+ *     Call backs all registered clients once a offload device is activated
+ */
+void cxgb3_add_clients(struct t3cdev *tdev)
+{
+       struct cxgb3_client *client;
+
+       mutex_lock(&cxgb3_db_lock);
+       list_for_each_entry(client, &client_list, client_list) {
+               if (client->add)
+                       client->add(tdev);
+       }
+       mutex_unlock(&cxgb3_db_lock);
+}
+
+/**
+ *     cxgb3_remove_clients - deactivates registered clients
+ *                            for an offload device
+ *     @tdev: the offload device
+ *
+ *     Call backs all registered clients once a offload device is deactivated
+ */
+void cxgb3_remove_clients(struct t3cdev *tdev)
+{
+       struct cxgb3_client *client;
+
+       mutex_lock(&cxgb3_db_lock);
+       list_for_each_entry(client, &client_list, client_list) {
+               if (client->remove)
+                       client->remove(tdev);
+       }
+       mutex_unlock(&cxgb3_db_lock);
+}
+
+static struct net_device *get_iff_from_mac(struct adapter *adapter,
+                                          const unsigned char *mac,
+                                          unsigned int vlan)
+{
+       int i;
+
+       for_each_port(adapter, i) {
+               const struct vlan_group *grp;
+               struct net_device *dev = adapter->port[i];
+               const struct port_info *p = netdev_priv(dev);
+
+               if (!memcmp(dev->dev_addr, mac, ETH_ALEN)) {
+                       if (vlan && vlan != VLAN_VID_MASK) {
+                               grp = p->vlan_grp;
+                               dev = grp ? grp->vlan_devices[vlan] : NULL;
+                       } else
+                               while (dev->master)
+                                       dev = dev->master;
+                       return dev;
+               }
+       }
+       return NULL;
+}
+
+static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req,
+                             void *data)
+{
+       int ret = 0;
+       struct ulp_iscsi_info *uiip = data;
+
+       switch (req) {
+       case ULP_ISCSI_GET_PARAMS:
+               uiip->pdev = adapter->pdev;
+               uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT);
+               uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT);
+               uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK);
+               /*
+                * On tx, the iscsi pdu has to be <= tx page size and has to
+                * fit into the Tx PM FIFO.
+                */
+               uiip->max_txsz = min(adapter->params.tp.tx_pg_size,
+                                    t3_read_reg(adapter, A_PM1_TX_CFG) >> 17);
+               /* on rx, the iscsi pdu has to be < rx page size and the
+                  whole pdu + cpl headers has to fit into one sge buffer */
+               uiip->max_rxsz = min_t(unsigned int,
+                                      adapter->params.tp.rx_pg_size,
+                                      (adapter->sge.qs[0].fl[1].buf_size -
+                                       sizeof(struct cpl_rx_data) * 2 -
+                                       sizeof(struct cpl_rx_data_ddp)));
+               break;
+       case ULP_ISCSI_SET_PARAMS:
+               t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask);
+               break;
+       default:
+               ret = -EOPNOTSUPP;
+       }
+       return ret;
+}
+
+/* Response queue used for RDMA events. */
+#define ASYNC_NOTIF_RSPQ 0
+
+static int cxgb_rdma_ctl(struct adapter *adapter, unsigned int req, void *data)
+{
+       int ret = 0;
+
+       switch (req) {
+       case RDMA_GET_PARAMS:{
+               struct rdma_info *req = data;
+               struct pci_dev *pdev = adapter->pdev;
+
+               req->udbell_physbase = pci_resource_start(pdev, 2);
+               req->udbell_len = pci_resource_len(pdev, 2);
+               req->tpt_base =
+                       t3_read_reg(adapter, A_ULPTX_TPT_LLIMIT);
+               req->tpt_top = t3_read_reg(adapter, A_ULPTX_TPT_ULIMIT);
+               req->pbl_base =
+                       t3_read_reg(adapter, A_ULPTX_PBL_LLIMIT);
+               req->pbl_top = t3_read_reg(adapter, A_ULPTX_PBL_ULIMIT);
+               req->rqt_base = t3_read_reg(adapter, A_ULPRX_RQ_LLIMIT);
+               req->rqt_top = t3_read_reg(adapter, A_ULPRX_RQ_ULIMIT);
+               req->kdb_addr = adapter->regs + A_SG_KDOORBELL;
+               req->pdev = pdev;
+               break;
+       }
+       case RDMA_CQ_OP:{
+               unsigned long flags;
+               struct rdma_cq_op *req = data;
+
+               /* may be called in any context */
+               spin_lock_irqsave(&adapter->sge.reg_lock, flags);
+               ret = t3_sge_cqcntxt_op(adapter, req->id, req->op,
+                                       req->credits);
+               spin_unlock_irqrestore(&adapter->sge.reg_lock, flags);
+               break;
+       }
+       case RDMA_GET_MEM:{
+               struct ch_mem_range *t = data;
+               struct mc7 *mem;
+
+               if ((t->addr & 7) || (t->len & 7))
+                       return -EINVAL;
+               if (t->mem_id == MEM_CM)
+                       mem = &adapter->cm;
+               else if (t->mem_id == MEM_PMRX)
+                       mem = &adapter->pmrx;
+               else if (t->mem_id == MEM_PMTX)
+                       mem = &adapter->pmtx;
+               else
+                       return -EINVAL;
+
+               ret =
+                       t3_mc7_bd_read(mem, t->addr / 8, t->len / 8,
+                                       (u64 *) t->buf);
+               if (ret)
+                       return ret;
+               break;
+       }
+       case RDMA_CQ_SETUP:{
+               struct rdma_cq_setup *req = data;
+
+               spin_lock_irq(&adapter->sge.reg_lock);
+               ret =
+                       t3_sge_init_cqcntxt(adapter, req->id,
+                                       req->base_addr, req->size,
+                                       ASYNC_NOTIF_RSPQ,
+                                       req->ovfl_mode, req->credits,
+                                       req->credit_thres);
+               spin_unlock_irq(&adapter->sge.reg_lock);
+               break;
+       }
+       case RDMA_CQ_DISABLE:
+               spin_lock_irq(&adapter->sge.reg_lock);
+               ret = t3_sge_disable_cqcntxt(adapter, *(unsigned int *)data);
+               spin_unlock_irq(&adapter->sge.reg_lock);
+               break;
+       case RDMA_CTRL_QP_SETUP:{
+               struct rdma_ctrlqp_setup *req = data;
+
+               spin_lock_irq(&adapter->sge.reg_lock);
+               ret = t3_sge_init_ecntxt(adapter, FW_RI_SGEEC_START, 0,
+                                               SGE_CNTXT_RDMA,
+                                               ASYNC_NOTIF_RSPQ,
+                                               req->base_addr, req->size,
+                                               FW_RI_TID_START, 1, 0);
+               spin_unlock_irq(&adapter->sge.reg_lock);
+               break;
+       }
+       default:
+               ret = -EOPNOTSUPP;
+       }
+       return ret;
+}
+
+static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data)
+{
+       struct adapter *adapter = tdev2adap(tdev);
+       struct tid_range *tid;
+       struct mtutab *mtup;
+       struct iff_mac *iffmacp;
+       struct ddp_params *ddpp;
+       struct adap_ports *ports;
+       int i;
+
+       switch (req) {
+       case GET_MAX_OUTSTANDING_WR:
+               *(unsigned int *)data = FW_WR_NUM;
+               break;
+       case GET_WR_LEN:
+               *(unsigned int *)data = WR_FLITS;
+               break;
+       case GET_TX_MAX_CHUNK:
+               *(unsigned int *)data = 1 << 20;        /* 1MB */
+               break;
+       case GET_TID_RANGE:
+               tid = data;
+               tid->num = t3_mc5_size(&adapter->mc5) -
+                   adapter->params.mc5.nroutes -
+                   adapter->params.mc5.nfilters - adapter->params.mc5.nservers;
+               tid->base = 0;
+               break;
+       case GET_STID_RANGE:
+               tid = data;
+               tid->num = adapter->params.mc5.nservers;
+               tid->base = t3_mc5_size(&adapter->mc5) - tid->num -
+                   adapter->params.mc5.nfilters - adapter->params.mc5.nroutes;
+               break;
+       case GET_L2T_CAPACITY:
+               *(unsigned int *)data = 2048;
+               break;
+       case GET_MTUS:
+               mtup = data;
+               mtup->size = NMTUS;
+               mtup->mtus = adapter->params.mtus;
+               break;
+       case GET_IFF_FROM_MAC:
+               iffmacp = data;
+               iffmacp->dev = get_iff_from_mac(adapter, iffmacp->mac_addr,
+                                               iffmacp->vlan_tag &
+                                               VLAN_VID_MASK);
+               break;
+       case GET_DDP_PARAMS:
+               ddpp = data;
+               ddpp->llimit = t3_read_reg(adapter, A_ULPRX_TDDP_LLIMIT);
+               ddpp->ulimit = t3_read_reg(adapter, A_ULPRX_TDDP_ULIMIT);
+               ddpp->tag_mask = t3_read_reg(adapter, A_ULPRX_TDDP_TAGMASK);
+               break;
+       case GET_PORTS:
+               ports = data;
+               ports->nports = adapter->params.nports;
+               for_each_port(adapter, i)
+                       ports->lldevs[i] = adapter->port[i];
+               break;
+       case ULP_ISCSI_GET_PARAMS:
+       case ULP_ISCSI_SET_PARAMS:
+               if (!offload_running(adapter))
+                       return -EAGAIN;
+               return cxgb_ulp_iscsi_ctl(adapter, req, data);
+       case RDMA_GET_PARAMS:
+       case RDMA_CQ_OP:
+       case RDMA_CQ_SETUP:
+       case RDMA_CQ_DISABLE:
+       case RDMA_CTRL_QP_SETUP:
+       case RDMA_GET_MEM:
+               if (!offload_running(adapter))
+                       return -EAGAIN;
+               return cxgb_rdma_ctl(adapter, req, data);
+       default:
+               return -EOPNOTSUPP;
+       }
+       return 0;
+}
+
+/*
+ * Dummy handler for Rx offload packets in case we get an offload packet before
+ * proper processing is setup.  This complains and drops the packet as it isn't
+ * normal to get offload packets at this stage.
+ */
+static int rx_offload_blackhole(struct t3cdev *dev, struct sk_buff **skbs,
+                               int n)
+{
+       CH_ERR(tdev2adap(dev), "%d unexpected offload packets, first data %u\n",
+              n, ntohl(*(u32 *)skbs[0]->data));
+       while (n--)
+               dev_kfree_skb_any(skbs[n]);
+       return 0;
+}
+
+static void dummy_neigh_update(struct t3cdev *dev, struct neighbour *neigh)
+{
+}
+
+void cxgb3_set_dummy_ops(struct t3cdev *dev)
+{
+       dev->recv = rx_offload_blackhole;
+       dev->neigh_update = dummy_neigh_update;
+}
+
+/*
+ * Free an active-open TID.
+ */
+void *cxgb3_free_atid(struct t3cdev *tdev, int atid)
+{
+       struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+       union active_open_entry *p = atid2entry(t, atid);
+       void *ctx = p->t3c_tid.ctx;
+
+       spin_lock_bh(&t->atid_lock);
+       p->next = t->afree;
+       t->afree = p;
+       t->atids_in_use--;
+       spin_unlock_bh(&t->atid_lock);
+
+       return ctx;
+}
+
+EXPORT_SYMBOL(cxgb3_free_atid);
+
+/*
+ * Free a server TID and return it to the free pool.
+ */
+void cxgb3_free_stid(struct t3cdev *tdev, int stid)
+{
+       struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+       union listen_entry *p = stid2entry(t, stid);
+
+       spin_lock_bh(&t->stid_lock);
+       p->next = t->sfree;
+       t->sfree = p;
+       t->stids_in_use--;
+       spin_unlock_bh(&t->stid_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_free_stid);
+
+void cxgb3_insert_tid(struct t3cdev *tdev, struct cxgb3_client *client,
+                     void *ctx, unsigned int tid)
+{
+       struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+       t->tid_tab[tid].client = client;
+       t->tid_tab[tid].ctx = ctx;
+       atomic_inc(&t->tids_in_use);
+}
+
+EXPORT_SYMBOL(cxgb3_insert_tid);
+
+/*
+ * Populate a TID_RELEASE WR.  The skb must be already propely sized.
+ */
+static inline void mk_tid_release(struct sk_buff *skb, unsigned int tid)
+{
+       struct cpl_tid_release *req;
+
+       skb->priority = CPL_PRIORITY_SETUP;
+       req = (struct cpl_tid_release *)__skb_put(skb, sizeof(*req));
+       req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+       OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_TID_RELEASE, tid));
+}
+
+static void t3_process_tid_release_list(struct work_struct *work)
+{
+       struct t3c_data *td = container_of(work, struct t3c_data,
+                                          tid_release_task);
+       struct sk_buff *skb;
+       struct t3cdev *tdev = td->dev;
+       
+
+       spin_lock_bh(&td->tid_release_lock);
+       while (td->tid_release_list) {
+               struct t3c_tid_entry *p = td->tid_release_list;
+
+               td->tid_release_list = (struct t3c_tid_entry *)p->ctx;
+               spin_unlock_bh(&td->tid_release_lock);
+
+               skb = alloc_skb(sizeof(struct cpl_tid_release),
+                               GFP_KERNEL | __GFP_NOFAIL);
+               mk_tid_release(skb, p - td->tid_maps.tid_tab);
+               cxgb3_ofld_send(tdev, skb);
+               p->ctx = NULL;
+               spin_lock_bh(&td->tid_release_lock);
+       }
+       spin_unlock_bh(&td->tid_release_lock);
+}
+
+/* use ctx as a next pointer in the tid release list */
+void cxgb3_queue_tid_release(struct t3cdev *tdev, unsigned int tid)
+{
+       struct t3c_data *td = T3C_DATA(tdev);
+       struct t3c_tid_entry *p = &td->tid_maps.tid_tab[tid];
+
+       spin_lock_bh(&td->tid_release_lock);
+       p->ctx = (void *)td->tid_release_list;
+       td->tid_release_list = p;
+       if (!p->ctx)
+               schedule_work(&td->tid_release_task);
+       spin_unlock_bh(&td->tid_release_lock);
+}
+
+EXPORT_SYMBOL(cxgb3_queue_tid_release);
+
+/*
+ * Remove a tid from the TID table.  A client may defer processing its last
+ * CPL message if it is locked at the time it arrives, and while the message
+ * sits in the client's backlog the TID may be reused for another connection.
+ * To handle this we atomically switch the TID association if it still points
+ * to the original client context.
+ */
+void cxgb3_remove_tid(struct t3cdev *tdev, void *ctx, unsigned int tid)
+{
+       struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+       BUG_ON(tid >= t->ntids);
+       if (tdev->type == T3A)
+               (void)cmpxchg(&t->tid_tab[tid].ctx, ctx, NULL);
+       else {
+               struct sk_buff *skb;
+
+               skb = alloc_skb(sizeof(struct cpl_tid_release), GFP_ATOMIC);
+               if (likely(skb)) {
+                       mk_tid_release(skb, tid);
+                       cxgb3_ofld_send(tdev, skb);
+                       t->tid_tab[tid].ctx = NULL;
+               } else
+                       cxgb3_queue_tid_release(tdev, tid);
+       }
+       atomic_dec(&t->tids_in_use);
+}
+
+EXPORT_SYMBOL(cxgb3_remove_tid);
+
+int cxgb3_alloc_atid(struct t3cdev *tdev, struct cxgb3_client *client,
+                    void *ctx)
+{
+       int atid = -1;
+       struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+       spin_lock_bh(&t->atid_lock);
+       if (t->afree) {
+               union active_open_entry *p = t->afree;
+
+               atid = (p - t->atid_tab) + t->atid_base;
+               t->afree = p->next;
+               p->t3c_tid.ctx = ctx;
+               p->t3c_tid.client = client;
+               t->atids_in_use++;
+       }
+       spin_unlock_bh(&t->atid_lock);
+       return atid;
+}
+
+EXPORT_SYMBOL(cxgb3_alloc_atid);
+
+int cxgb3_alloc_stid(struct t3cdev *tdev, struct cxgb3_client *client,
+                    void *ctx)
+{
+       int stid = -1;
+       struct tid_info *t = &(T3C_DATA(tdev))->tid_maps;
+
+       spin_lock_bh(&t->stid_lock);
+       if (t->sfree) {
+               union listen_entry *p = t->sfree;
+
+               stid = (p - t->stid_tab) + t->stid_base;
+               t->sfree = p->next;
+               p->t3c_tid.ctx = ctx;
+               p->t3c_tid.client = client;
+               t->stids_in_use++;
+       }
+       spin_unlock_bh(&t->stid_lock);
+       return stid;
+}
+
+EXPORT_SYMBOL(cxgb3_alloc_stid);
+
+static int do_smt_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+       struct cpl_smt_write_rpl *rpl = cplhdr(skb);
+
+       if (rpl->status != CPL_ERR_NONE)
+               printk(KERN_ERR
+                      "Unexpected SMT_WRITE_RPL status %u for entry %u\n",
+                      rpl->status, GET_TID(rpl));
+
+       return CPL_RET_BUF_DONE;
+}
+
+static int do_l2t_write_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+       struct cpl_l2t_write_rpl *rpl = cplhdr(skb);
+
+       if (rpl->status != CPL_ERR_NONE)
+               printk(KERN_ERR
+                      "Unexpected L2T_WRITE_RPL status %u for entry %u\n",
+                      rpl->status, GET_TID(rpl));
+
+       return CPL_RET_BUF_DONE;
+}
+
+static int do_act_open_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+       struct cpl_act_open_rpl *rpl = cplhdr(skb);
+       unsigned int atid = G_TID(ntohl(rpl->atid));
+       struct t3c_tid_entry *t3c_tid;
+
+       t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+       if (t3c_tid->ctx && t3c_tid->client && t3c_tid->client->handlers &&
+           t3c_tid->client->handlers[CPL_ACT_OPEN_RPL]) {
+               return t3c_tid->client->handlers[CPL_ACT_OPEN_RPL] (dev, skb,
+                                                                   t3c_tid->
+                                                                   ctx);
+       } else {
+               printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+                      dev->name, CPL_ACT_OPEN_RPL);
+               return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+       }
+}
+
+static int do_stid_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+       union opcode_tid *p = cplhdr(skb);
+       unsigned int stid = G_TID(ntohl(p->opcode_tid));
+       struct t3c_tid_entry *t3c_tid;
+
+       t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
+       if (t3c_tid->ctx && t3c_tid->client->handlers &&
+           t3c_tid->client->handlers[p->opcode]) {
+               return t3c_tid->client->handlers[p->opcode] (dev, skb,
+                                                            t3c_tid->ctx);
+       } else {
+               printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+                      dev->name, p->opcode);
+               return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+       }
+}
+
+static int do_hwtid_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+       union opcode_tid *p = cplhdr(skb);
+       unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
+       struct t3c_tid_entry *t3c_tid;
+
+       t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+       if (t3c_tid->ctx && t3c_tid->client->handlers &&
+           t3c_tid->client->handlers[p->opcode]) {
+               return t3c_tid->client->handlers[p->opcode]
+                   (dev, skb, t3c_tid->ctx);
+       } else {
+               printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+                      dev->name, p->opcode);
+               return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+       }
+}
+
+static int do_cr(struct t3cdev *dev, struct sk_buff *skb)
+{
+       struct cpl_pass_accept_req *req = cplhdr(skb);
+       unsigned int stid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+       struct t3c_tid_entry *t3c_tid;
+
+       t3c_tid = lookup_stid(&(T3C_DATA(dev))->tid_maps, stid);
+       if (t3c_tid->ctx && t3c_tid->client->handlers &&
+           t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]) {
+               return t3c_tid->client->handlers[CPL_PASS_ACCEPT_REQ]
+                   (dev, skb, t3c_tid->ctx);
+       } else {
+               printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+                      dev->name, CPL_PASS_ACCEPT_REQ);
+               return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+       }
+}
+
+static int do_abort_req_rss(struct t3cdev *dev, struct sk_buff *skb)
+{
+       union opcode_tid *p = cplhdr(skb);
+       unsigned int hwtid = G_TID(ntohl(p->opcode_tid));
+       struct t3c_tid_entry *t3c_tid;
+
+       t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+       if (t3c_tid->ctx && t3c_tid->client->handlers &&
+           t3c_tid->client->handlers[p->opcode]) {
+               return t3c_tid->client->handlers[p->opcode]
+                   (dev, skb, t3c_tid->ctx);
+       } else {
+               struct cpl_abort_req_rss *req = cplhdr(skb);
+               struct cpl_abort_rpl *rpl;
+
+               struct sk_buff *skb =
+                   alloc_skb(sizeof(struct cpl_abort_rpl), GFP_ATOMIC);
+               if (!skb) {
+                       printk("do_abort_req_rss: couldn't get skb!\n");
+                       goto out;
+               }
+               skb->priority = CPL_PRIORITY_DATA;
+               __skb_put(skb, sizeof(struct cpl_abort_rpl));
+               rpl = cplhdr(skb);
+               rpl->wr.wr_hi =
+                   htonl(V_WR_OP(FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL));
+               rpl->wr.wr_lo = htonl(V_WR_TID(GET_TID(req)));
+               OPCODE_TID(rpl) =
+                   htonl(MK_OPCODE_TID(CPL_ABORT_RPL, GET_TID(req)));
+               rpl->cmd = req->status;
+               cxgb3_ofld_send(dev, skb);
+out:
+               return CPL_RET_BUF_DONE;
+       }
+}
+
+static int do_act_establish(struct t3cdev *dev, struct sk_buff *skb)
+{
+       struct cpl_act_establish *req = cplhdr(skb);
+       unsigned int atid = G_PASS_OPEN_TID(ntohl(req->tos_tid));
+       struct t3c_tid_entry *t3c_tid;
+
+       t3c_tid = lookup_atid(&(T3C_DATA(dev))->tid_maps, atid);
+       if (t3c_tid->ctx && t3c_tid->client->handlers &&
+           t3c_tid->client->handlers[CPL_ACT_ESTABLISH]) {
+               return t3c_tid->client->handlers[CPL_ACT_ESTABLISH]
+                   (dev, skb, t3c_tid->ctx);
+       } else {
+               printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+                      dev->name, CPL_PASS_ACCEPT_REQ);
+               return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+       }
+}
+
+static int do_set_tcb_rpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+       struct cpl_set_tcb_rpl *rpl = cplhdr(skb);
+
+       if (rpl->status != CPL_ERR_NONE)
+               printk(KERN_ERR
+                      "Unexpected SET_TCB_RPL status %u for tid %u\n",
+                      rpl->status, GET_TID(rpl));
+       return CPL_RET_BUF_DONE;
+}
+
+static int do_trace(struct t3cdev *dev, struct sk_buff *skb)
+{
+       struct cpl_trace_pkt *p = cplhdr(skb);
+
+       skb->protocol = 0xffff;
+       skb->dev = dev->lldev;
+       skb_pull(skb, sizeof(*p));
+       skb->mac.raw = skb->data;
+       netif_receive_skb(skb);
+       return 0;
+}
+
+static int do_term(struct t3cdev *dev, struct sk_buff *skb)
+{
+       unsigned int hwtid = ntohl(skb->priority) >> 8 & 0xfffff;
+       unsigned int opcode = G_OPCODE(ntohl(skb->csum));
+       struct t3c_tid_entry *t3c_tid;
+
+       t3c_tid = lookup_tid(&(T3C_DATA(dev))->tid_maps, hwtid);
+       if (t3c_tid->ctx && t3c_tid->client->handlers &&
+           t3c_tid->client->handlers[opcode]) {
+               return t3c_tid->client->handlers[opcode] (dev, skb,
+                                                         t3c_tid->ctx);
+       } else {
+               printk(KERN_ERR "%s: received clientless CPL command 0x%x\n",
+                      dev->name, opcode);
+               return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+       }
+}
+
+static int nb_callback(struct notifier_block *self, unsigned long event,
+                      void *ctx)
+{
+       switch (event) {
+       case (NETEVENT_NEIGH_UPDATE):{
+               cxgb_neigh_update((struct neighbour *)ctx);
+               break;
+       }
+       case (NETEVENT_PMTU_UPDATE):
+               break;
+       case (NETEVENT_REDIRECT):{
+               struct netevent_redirect *nr = ctx;
+               cxgb_redirect(nr->old, nr->new);
+               cxgb_neigh_update(nr->new->neighbour);
+               break;
+       }
+       default:
+               break;
+       }
+       return 0;
+}
+
+static struct notifier_block nb = {
+       .notifier_call = nb_callback
+};
+
+/*
+ * Process a received packet with an unknown/unexpected CPL opcode.
+ */
+static int do_bad_cpl(struct t3cdev *dev, struct sk_buff *skb)
+{
+       printk(KERN_ERR "%s: received bad CPL command 0x%x\n", dev->name,
+              *skb->data);
+       return CPL_RET_BUF_DONE | CPL_RET_BAD_MSG;
+}
+
+/*
+ * Handlers for each CPL opcode
+ */
+static cpl_handler_func cpl_handlers[NUM_CPL_CMDS];
+
+/*
+ * Add a new handler to the CPL dispatch table.  A NULL handler may be supplied
+ * to unregister an existing handler.
+ */
+void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h)
+{
+       if (opcode < NUM_CPL_CMDS)
+               cpl_handlers[opcode] = h ? h : do_bad_cpl;
+       else
+               printk(KERN_ERR "T3C: handler registration for "
+                      "opcode %x failed\n", opcode);
+}
+
+EXPORT_SYMBOL(t3_register_cpl_handler);
+
+/*
+ * T3CDEV's receive method.
+ */
+int process_rx(struct t3cdev *dev, struct sk_buff **skbs, int n)
+{
+       while (n--) {
+               struct sk_buff *skb = *skbs++;
+               unsigned int opcode = G_OPCODE(ntohl(skb->csum));
+               int ret = cpl_handlers[opcode] (dev, skb);
+
+#if VALIDATE_TID
+               if (ret & CPL_RET_UNKNOWN_TID) {
+                       union opcode_tid *p = cplhdr(skb);
+
+                       printk(KERN_ERR "%s: CPL message (opcode %u) had "
+                              "unknown TID %u\n", dev->name, opcode,
+                              G_TID(ntohl(p->opcode_tid)));
+               }
+#endif
+               if (ret & CPL_RET_BUF_DONE)
+                       kfree_skb(skb);
+       }
+       return 0;
+}
+
+/*
+ * Sends an sk_buff to a T3C driver after dealing with any active network taps.
+ */
+int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb)
+{
+       int r;
+
+       local_bh_disable();
+       r = dev->send(dev, skb);
+       local_bh_enable();
+       return r;
+}
+
+EXPORT_SYMBOL(cxgb3_ofld_send);
+
+static int is_offloading(struct net_device *dev)
+{
+       struct adapter *adapter;
+       int i;
+
+       read_lock_bh(&adapter_list_lock);
+       list_for_each_entry(adapter, &adapter_list, adapter_list) {
+               for_each_port(adapter, i) {
+                       if (dev == adapter->port[i]) {
+                               read_unlock_bh(&adapter_list_lock);
+                               return 1;
+                       }
+               }
+       }
+       read_unlock_bh(&adapter_list_lock);
+       return 0;
+}
+
+void cxgb_neigh_update(struct neighbour *neigh)
+{
+       struct net_device *dev = neigh->dev;
+
+       if (dev && (is_offloading(dev))) {
+               struct t3cdev *tdev = T3CDEV(dev);
+
+               BUG_ON(!tdev);
+               t3_l2t_update(tdev, neigh);
+       }
+}
+
+static void set_l2t_ix(struct t3cdev *tdev, u32 tid, struct l2t_entry *e)
+{
+       struct sk_buff *skb;
+       struct cpl_set_tcb_field *req;
+
+       skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
+       if (!skb) {
+               printk(KERN_ERR "%s: cannot allocate skb!\n", __FUNCTION__);
+               return;
+       }
+       skb->priority = CPL_PRIORITY_CONTROL;
+       req = (struct cpl_set_tcb_field *)skb_put(skb, sizeof(*req));
+       req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+       OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
+       req->reply = 0;
+       req->cpu_idx = 0;
+       req->word = htons(W_TCB_L2T_IX);
+       req->mask = cpu_to_be64(V_TCB_L2T_IX(M_TCB_L2T_IX));
+       req->val = cpu_to_be64(V_TCB_L2T_IX(e->idx));
+       tdev->send(tdev, skb);
+}
+
+void cxgb_redirect(struct dst_entry *old, struct dst_entry *new)
+{
+       struct net_device *olddev, *newdev;
+       struct tid_info *ti;
+       struct t3cdev *tdev;
+       u32 tid;
+       int update_tcb;
+       struct l2t_entry *e;
+       struct t3c_tid_entry *te;
+
+       olddev = old->neighbour->dev;
+       newdev = new->neighbour->dev;
+       if (!is_offloading(olddev))
+               return;
+       if (!is_offloading(newdev)) {
+               printk(KERN_WARNING "%s: Redirect to non-offload"
+                      "device ignored.\n", __FUNCTION__);
+               return;
+       }
+       tdev = T3CDEV(olddev);
+       BUG_ON(!tdev);
+       if (tdev != T3CDEV(newdev)) {
+               printk(KERN_WARNING "%s: Redirect to different "
+                      "offload device ignored.\n", __FUNCTION__);
+               return;
+       }
+
+       /* Add new L2T entry */
+       e = t3_l2t_get(tdev, new->neighbour, newdev);
+       if (!e) {
+               printk(KERN_ERR "%s: couldn't allocate new l2t entry!\n",
+                      __FUNCTION__);
+               return;
+       }
+
+       /* Walk tid table and notify clients of dst change. */
+       ti = &(T3C_DATA(tdev))->tid_maps;
+       for (tid = 0; tid < ti->ntids; tid++) {
+               te = lookup_tid(ti, tid);
+               BUG_ON(!te);
+               if (te->ctx && te->client && te->client->redirect) {
+                       update_tcb = te->client->redirect(te->ctx, old, new, e);
+                       if (update_tcb) {
+                               l2t_hold(L2DATA(tdev), e);
+                               set_l2t_ix(tdev, tid, e);
+                       }
+               }
+       }
+       l2t_release(L2DATA(tdev), e);
+}
+
+/*
+ * Allocate a chunk of memory using kmalloc or, if that fails, vmalloc.
+ * The allocated memory is cleared.
+ */
+void *cxgb_alloc_mem(unsigned long size)
+{
+       void *p = kmalloc(size, GFP_KERNEL);
+
+       if (!p)
+               p = vmalloc(size);
+       if (p)
+               memset(p, 0, size);
+       return p;
+}
+
+/*
+ * Free memory allocated through t3_alloc_mem().
+ */
+void cxgb_free_mem(void *addr)
+{
+       unsigned long p = (unsigned long)addr;
+
+       if (p >= VMALLOC_START && p < VMALLOC_END)
+               vfree(addr);
+       else
+               kfree(addr);
+}
+
+/*
+ * Allocate and initialize the TID tables.  Returns 0 on success.
+ */
+static int init_tid_tabs(struct tid_info *t, unsigned int ntids,
+                        unsigned int natids, unsigned int nstids,
+                        unsigned int atid_base, unsigned int stid_base)
+{
+       unsigned long size = ntids * sizeof(*t->tid_tab) +
+           natids * sizeof(*t->atid_tab) + nstids * sizeof(*t->stid_tab);
+
+       t->tid_tab = cxgb_alloc_mem(size);
+       if (!t->tid_tab)
+               return -ENOMEM;
+
+       t->stid_tab = (union listen_entry *)&t->tid_tab[ntids];
+       t->atid_tab = (union active_open_entry *)&t->stid_tab[nstids];
+       t->ntids = ntids;
+       t->nstids = nstids;
+       t->stid_base = stid_base;
+       t->sfree = NULL;
+       t->natids = natids;
+       t->atid_base = atid_base;
+       t->afree = NULL;
+       t->stids_in_use = t->atids_in_use = 0;
+       atomic_set(&t->tids_in_use, 0);
+       spin_lock_init(&t->stid_lock);
+       spin_lock_init(&t->atid_lock);
+
+       /*
+        * Setup the free lists for stid_tab and atid_tab.
+        */
+       if (nstids) {
+               while (--nstids)
+                       t->stid_tab[nstids - 1].next = &t->stid_tab[nstids];
+               t->sfree = t->stid_tab;
+       }
+       if (natids) {
+               while (--natids)
+                       t->atid_tab[natids - 1].next = &t->atid_tab[natids];
+               t->afree = t->atid_tab;
+       }
+       return 0;
+}
+
+static void free_tid_maps(struct tid_info *t)
+{
+       cxgb_free_mem(t->tid_tab);
+}
+
+static inline void add_adapter(struct adapter *adap)
+{
+       write_lock_bh(&adapter_list_lock);
+       list_add_tail(&adap->adapter_list, &adapter_list);
+       write_unlock_bh(&adapter_list_lock);
+}
+
+static inline void remove_adapter(struct adapter *adap)
+{
+       write_lock_bh(&adapter_list_lock);
+       list_del(&adap->adapter_list);
+       write_unlock_bh(&adapter_list_lock);
+}
+
+int cxgb3_offload_activate(struct adapter *adapter)
+{
+       struct t3cdev *dev = &adapter->tdev;
+       int natids, err;
+       struct t3c_data *t;
+       struct tid_range stid_range, tid_range;
+       struct mtutab mtutab;
+       unsigned int l2t_capacity;
+
+       t = kcalloc(1, sizeof(*t), GFP_KERNEL);
+       if (!t)
+               return -ENOMEM;
+
+       err = -EOPNOTSUPP;
+       if (dev->ctl(dev, GET_TX_MAX_CHUNK, &t->tx_max_chunk) < 0 ||
+           dev->ctl(dev, GET_MAX_OUTSTANDING_WR, &t->max_wrs) < 0 ||
+           dev->ctl(dev, GET_L2T_CAPACITY, &l2t_capacity) < 0 ||
+           dev->ctl(dev, GET_MTUS, &mtutab) < 0 ||
+           dev->ctl(dev, GET_TID_RANGE, &tid_range) < 0 ||
+           dev->ctl(dev, GET_STID_RANGE, &stid_range) < 0)
+               goto out_free;
+
+       err = -ENOMEM;
+       L2DATA(dev) = t3_init_l2t(l2t_capacity);
+       if (!L2DATA(dev))
+               goto out_free;
+
+       natids = min(tid_range.num / 2, MAX_ATIDS);
+       err = init_tid_tabs(&t->tid_maps, tid_range.num, natids,
+                           stid_range.num, ATID_BASE, stid_range.base);
+       if (err)
+               goto out_free_l2t;
+
+       t->mtus = mtutab.mtus;
+       t->nmtus = mtutab.size;
+
+       INIT_WORK(&t->tid_release_task, t3_process_tid_release_list);
+       spin_lock_init(&t->tid_release_lock);
+       INIT_LIST_HEAD(&t->list_node);
+       t->dev = dev;
+
+       T3C_DATA(dev) = t;
+       dev->recv = process_rx;
+       dev->neigh_update = t3_l2t_update;
+
+       /* Register netevent handler once */
+       if (list_empty(&adapter_list))
+               register_netevent_notifier(&nb);
+
+       add_adapter(adapter);
+       return 0;
+
+out_free_l2t:
+       t3_free_l2t(L2DATA(dev));
+       L2DATA(dev) = NULL;
+out_free:
+       kfree(t);
+       return err;
+}
+
+void cxgb3_offload_deactivate(struct adapter *adapter)
+{
+       struct t3cdev *tdev = &adapter->tdev;
+       struct t3c_data *t = T3C_DATA(tdev);
+
+       remove_adapter(adapter);
+       if (list_empty(&adapter_list))
+               unregister_netevent_notifier(&nb);
+
+       free_tid_maps(&t->tid_maps);
+       T3C_DATA(tdev) = NULL;
+       t3_free_l2t(L2DATA(tdev));
+       L2DATA(tdev) = NULL;
+       kfree(t);
+}
+
+static inline void register_tdev(struct t3cdev *tdev)
+{
+       static int unit;
+
+       mutex_lock(&cxgb3_db_lock);
+       snprintf(tdev->name, sizeof(tdev->name), "ofld_dev%d", unit++);
+       list_add_tail(&tdev->ofld_dev_list, &ofld_dev_list);
+       mutex_unlock(&cxgb3_db_lock);
+}
+
+static inline void unregister_tdev(struct t3cdev *tdev)
+{
+       mutex_lock(&cxgb3_db_lock);
+       list_del(&tdev->ofld_dev_list);
+       mutex_unlock(&cxgb3_db_lock);
+}
+
+void __devinit cxgb3_adapter_ofld(struct adapter *adapter)
+{
+       struct t3cdev *tdev = &adapter->tdev;
+
+       INIT_LIST_HEAD(&tdev->ofld_dev_list);
+
+       cxgb3_set_dummy_ops(tdev);
+       tdev->send = t3_offload_tx;
+       tdev->ctl = cxgb_offload_ctl;
+       tdev->type = adapter->params.rev == 0 ? T3A : T3B;
+
+       register_tdev(tdev);
+}
+
+void __devexit cxgb3_adapter_unofld(struct adapter *adapter)
+{
+       struct t3cdev *tdev = &adapter->tdev;
+
+       tdev->recv = NULL;
+       tdev->neigh_update = NULL;
+
+       unregister_tdev(tdev);
+}
+
+void __init cxgb3_offload_init(void)
+{
+       int i;
+
+       for (i = 0; i < NUM_CPL_CMDS; ++i)
+               cpl_handlers[i] = do_bad_cpl;
+
+       t3_register_cpl_handler(CPL_SMT_WRITE_RPL, do_smt_write_rpl);
+       t3_register_cpl_handler(CPL_L2T_WRITE_RPL, do_l2t_write_rpl);
+       t3_register_cpl_handler(CPL_PASS_OPEN_RPL, do_stid_rpl);
+       t3_register_cpl_handler(CPL_CLOSE_LISTSRV_RPL, do_stid_rpl);
+       t3_register_cpl_handler(CPL_PASS_ACCEPT_REQ, do_cr);
+       t3_register_cpl_handler(CPL_PASS_ESTABLISH, do_hwtid_rpl);
+       t3_register_cpl_handler(CPL_ABORT_RPL_RSS, do_hwtid_rpl);
+       t3_register_cpl_handler(CPL_ABORT_RPL, do_hwtid_rpl);
+       t3_register_cpl_handler(CPL_RX_URG_NOTIFY, do_hwtid_rpl);
+       t3_register_cpl_handler(CPL_RX_DATA, do_hwtid_rpl);
+       t3_register_cpl_handler(CPL_TX_DATA_ACK, do_hwtid_rpl);
+       t3_register_cpl_handler(CPL_TX_DMA_ACK, do_hwtid_rpl);
+       t3_register_cpl_handler(CPL_ACT_OPEN_RPL, do_act_open_rpl);
+       t3_register_cpl_handler(CPL_PEER_CLOSE, do_hwtid_rpl);
+       t3_register_cpl_handler(CPL_CLOSE_CON_RPL, do_hwtid_rpl);
+       t3_register_cpl_handler(CPL_ABORT_REQ_RSS, do_abort_req_rss);
+       t3_register_cpl_handler(CPL_ACT_ESTABLISH, do_act_establish);
+       t3_register_cpl_handler(CPL_SET_TCB_RPL, do_set_tcb_rpl);
+       t3_register_cpl_handler(CPL_RDMA_TERMINATE, do_term);
+       t3_register_cpl_handler(CPL_RDMA_EC_STATUS, do_hwtid_rpl);
+       t3_register_cpl_handler(CPL_TRACE_PKT, do_trace);
+       t3_register_cpl_handler(CPL_RX_DATA_DDP, do_hwtid_rpl);
+       t3_register_cpl_handler(CPL_RX_DDP_COMPLETE, do_hwtid_rpl);
+       t3_register_cpl_handler(CPL_ISCSI_HDR, do_hwtid_rpl);
+}
diff --git a/drivers/net/cxgb3/cxgb3_offload.h b/drivers/net/cxgb3/cxgb3_offload.h
new file mode 100644 (file)
index 0000000..0e6beb6
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2006-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CXGB3_OFFLOAD_H
+#define _CXGB3_OFFLOAD_H
+
+#include <linux/list.h>
+#include <linux/skbuff.h>
+
+#include "l2t.h"
+
+#include "t3cdev.h"
+#include "t3_cpl.h"
+
+struct adapter;
+
+void cxgb3_offload_init(void);
+
+void cxgb3_adapter_ofld(struct adapter *adapter);
+void cxgb3_adapter_unofld(struct adapter *adapter);
+int cxgb3_offload_activate(struct adapter *adapter);
+void cxgb3_offload_deactivate(struct adapter *adapter);
+
+void cxgb3_set_dummy_ops(struct t3cdev *dev);
+
+/*
+ * Client registration.  Users of T3 driver must register themselves.
+ * The T3 driver will call the add function of every client for each T3
+ * adapter activated, passing up the t3cdev ptr.  Each client fills out an
+ * array of callback functions to process CPL messages.
+ */
+
+void cxgb3_register_client(struct cxgb3_client *client);
+void cxgb3_unregister_client(struct cxgb3_client *client);
+void cxgb3_add_clients(struct t3cdev *tdev);
+void cxgb3_remove_clients(struct t3cdev *tdev);
+
+typedef int (*cxgb3_cpl_handler_func)(struct t3cdev *dev,
+                                     struct sk_buff *skb, void *ctx);
+
+struct cxgb3_client {
+       char *name;
+       void (*add) (struct t3cdev *);
+       void (*remove) (struct t3cdev *);
+       cxgb3_cpl_handler_func *handlers;
+       int (*redirect)(void *ctx, struct dst_entry *old,
+                       struct dst_entry *new, struct l2t_entry *l2t);
+       struct list_head client_list;
+};
+
+/*
+ * TID allocation services.
+ */
+int cxgb3_alloc_atid(struct t3cdev *dev, struct cxgb3_client *client,
+                    void *ctx);
+int cxgb3_alloc_stid(struct t3cdev *dev, struct cxgb3_client *client,
+                    void *ctx);
+void *cxgb3_free_atid(struct t3cdev *dev, int atid);
+void cxgb3_free_stid(struct t3cdev *dev, int stid);
+void cxgb3_insert_tid(struct t3cdev *dev, struct cxgb3_client *client,
+                     void *ctx, unsigned int tid);
+void cxgb3_queue_tid_release(struct t3cdev *dev, unsigned int tid);
+void cxgb3_remove_tid(struct t3cdev *dev, void *ctx, unsigned int tid);
+
+struct t3c_tid_entry {
+       struct cxgb3_client *client;
+       void *ctx;
+};
+
+/* CPL message priority levels */
+enum {
+       CPL_PRIORITY_DATA = 0,  /* data messages */
+       CPL_PRIORITY_SETUP = 1, /* connection setup messages */
+       CPL_PRIORITY_TEARDOWN = 0,      /* connection teardown messages */
+       CPL_PRIORITY_LISTEN = 1,        /* listen start/stop messages */
+       CPL_PRIORITY_ACK = 1,   /* RX ACK messages */
+       CPL_PRIORITY_CONTROL = 1        /* offload control messages */
+};
+
+/* Flags for return value of CPL message handlers */
+enum {
+       CPL_RET_BUF_DONE = 1, /* buffer processing done, buffer may be freed */
+       CPL_RET_BAD_MSG = 2,  /* bad CPL message (e.g., unknown opcode) */
+       CPL_RET_UNKNOWN_TID = 4 /* unexpected unknown TID */
+};
+
+typedef int (*cpl_handler_func)(struct t3cdev *dev, struct sk_buff *skb);
+
+/*
+ * Returns a pointer to the first byte of the CPL header in an sk_buff that
+ * contains a CPL message.
+ */
+static inline void *cplhdr(struct sk_buff *skb)
+{
+       return skb->data;
+}
+
+void t3_register_cpl_handler(unsigned int opcode, cpl_handler_func h);
+
+union listen_entry {
+       struct t3c_tid_entry t3c_tid;
+       union listen_entry *next;
+};
+
+union active_open_entry {
+       struct t3c_tid_entry t3c_tid;
+       union active_open_entry *next;
+};
+
+/*
+ * Holds the size, base address, free list start, etc of the TID, server TID,
+ * and active-open TID tables for a offload device.
+ * The tables themselves are allocated dynamically.
+ */
+struct tid_info {
+       struct t3c_tid_entry *tid_tab;
+       unsigned int ntids;
+       atomic_t tids_in_use;
+
+       union listen_entry *stid_tab;
+       unsigned int nstids;
+       unsigned int stid_base;
+
+       union active_open_entry *atid_tab;
+       unsigned int natids;
+       unsigned int atid_base;
+
+       /*
+        * The following members are accessed R/W so we put them in their own
+        * cache lines.
+        *
+        * XXX We could combine the atid fields above with the lock here since
+        * atids are use once (unlike other tids).  OTOH the above fields are
+        * usually in cache due to tid_tab.
+        */
+       spinlock_t atid_lock ____cacheline_aligned_in_smp;
+       union active_open_entry *afree;
+       unsigned int atids_in_use;
+
+       spinlock_t stid_lock ____cacheline_aligned;
+       union listen_entry *sfree;
+       unsigned int stids_in_use;
+};
+
+struct t3c_data {
+       struct list_head list_node;
+       struct t3cdev *dev;
+       unsigned int tx_max_chunk;      /* max payload for TX_DATA */
+       unsigned int max_wrs;   /* max in-flight WRs per connection */
+       unsigned int nmtus;
+       const unsigned short *mtus;
+       struct tid_info tid_maps;
+
+       struct t3c_tid_entry *tid_release_list;
+       spinlock_t tid_release_lock;
+       struct work_struct tid_release_task;
+};
+
+/*
+ * t3cdev -> t3c_data accessor
+ */
+#define T3C_DATA(dev) (*(struct t3c_data **)&(dev)->l4opt)
+
+#endif
diff --git a/drivers/net/cxgb3/firmware_exports.h b/drivers/net/cxgb3/firmware_exports.h
new file mode 100644 (file)
index 0000000..6a835f6
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _FIRMWARE_EXPORTS_H_
+#define _FIRMWARE_EXPORTS_H_
+
+/* WR OPCODES supported by the firmware.
+ */
+#define        FW_WROPCODE_FORWARD                     0x01
+#define FW_WROPCODE_BYPASS                     0x05
+
+#define FW_WROPCODE_TUNNEL_TX_PKT              0x03
+
+#define FW_WROPOCDE_ULPTX_DATA_SGL             0x00
+#define FW_WROPCODE_ULPTX_MEM_READ             0x02
+#define FW_WROPCODE_ULPTX_PKT                  0x04
+#define FW_WROPCODE_ULPTX_INVALIDATE           0x06
+
+#define FW_WROPCODE_TUNNEL_RX_PKT              0x07
+
+#define FW_WROPCODE_OFLD_GETTCB_RPL            0x08
+#define FW_WROPCODE_OFLD_CLOSE_CON             0x09
+#define FW_WROPCODE_OFLD_TP_ABORT_CON_REQ      0x0A
+#define FW_WROPCODE_OFLD_HOST_ABORT_CON_RPL    0x0F
+#define FW_WROPCODE_OFLD_HOST_ABORT_CON_REQ    0x0B
+#define FW_WROPCODE_OFLD_TP_ABORT_CON_RPL      0x0C
+#define FW_WROPCODE_OFLD_TX_DATA               0x0D
+#define FW_WROPCODE_OFLD_TX_DATA_ACK           0x0E
+
+#define FW_WROPCODE_RI_RDMA_INIT               0x10
+#define FW_WROPCODE_RI_RDMA_WRITE              0x11
+#define FW_WROPCODE_RI_RDMA_READ_REQ           0x12
+#define FW_WROPCODE_RI_RDMA_READ_RESP          0x13
+#define FW_WROPCODE_RI_SEND                    0x14
+#define FW_WROPCODE_RI_TERMINATE               0x15
+#define FW_WROPCODE_RI_RDMA_READ               0x16
+#define FW_WROPCODE_RI_RECEIVE                 0x17
+#define FW_WROPCODE_RI_BIND_MW                 0x18
+#define FW_WROPCODE_RI_FASTREGISTER_MR         0x19
+#define FW_WROPCODE_RI_LOCAL_INV               0x1A
+#define FW_WROPCODE_RI_MODIFY_QP               0x1B
+#define FW_WROPCODE_RI_BYPASS                  0x1C
+
+#define FW_WROPOCDE_RSVD                       0x1E
+
+#define FW_WROPCODE_SGE_EGRESSCONTEXT_RR       0x1F
+
+#define FW_WROPCODE_MNGT                       0x1D
+#define FW_MNGTOPCODE_PKTSCHED_SET             0x00
+
+/* Maximum size of a WR sent from the host, limited by the SGE. 
+ *
+ * Note: WR coming from ULP or TP are only limited by CIM. 
+ */
+#define FW_WR_SIZE                     128
+
+/* Maximum number of outstanding WRs sent from the host. Value must be
+ * programmed in the CTRL/TUNNEL/QP SGE Egress Context and used by 
+ * offload modules to limit the number of WRs per connection.
+ */
+#define FW_T3_WR_NUM                   16
+#define FW_N3_WR_NUM                   7
+
+#ifndef N3
+# define FW_WR_NUM                     FW_T3_WR_NUM
+#else
+# define FW_WR_NUM                     FW_N3_WR_NUM
+#endif
+
+/* FW_TUNNEL_NUM corresponds to the number of supported TUNNEL Queues. These
+ * queues must start at SGE Egress Context FW_TUNNEL_SGEEC_START and must
+ * start at 'TID' (or 'uP Token') FW_TUNNEL_TID_START.
+ *
+ * Ingress Traffic (e.g. DMA completion credit)  for TUNNEL Queue[i] is sent 
+ * to RESP Queue[i].
+ */
+#define FW_TUNNEL_NUM                  8
+#define FW_TUNNEL_SGEEC_START          8
+#define FW_TUNNEL_TID_START            65544
+
+/* FW_CTRL_NUM corresponds to the number of supported CTRL Queues. These queues
+ * must start at SGE Egress Context FW_CTRL_SGEEC_START and must start at 'TID'
+ * (or 'uP Token') FW_CTRL_TID_START.
+ *
+ * Ingress Traffic for CTRL Queue[i] is sent to RESP Queue[i].
+ */
+#define FW_CTRL_NUM                    8
+#define FW_CTRL_SGEEC_START            65528
+#define FW_CTRL_TID_START              65536
+
+/* FW_OFLD_NUM corresponds to the number of supported OFFLOAD Queues. These 
+ * queues must start at SGE Egress Context FW_OFLD_SGEEC_START. 
+ * 
+ * Note: the 'uP Token' in the SGE Egress Context fields is irrelevant for 
+ * OFFLOAD Queues, as the host is responsible for providing the correct TID in
+ * every WR.
+ *
+ * Ingress Trafffic for OFFLOAD Queue[i] is sent to RESP Queue[i].
+ */
+#define FW_OFLD_NUM                    8
+#define FW_OFLD_SGEEC_START            0
+
+/*
+ * 
+ */
+#define FW_RI_NUM                      1
+#define FW_RI_SGEEC_START              65527
+#define FW_RI_TID_START                        65552
+
+/*
+ * The RX_PKT_TID 
+ */
+#define FW_RX_PKT_NUM                  1
+#define FW_RX_PKT_TID_START            65553
+
+/* FW_WRC_NUM corresponds to the number of Work Request Context that supported
+ * by the firmware.
+ */
+#define FW_WRC_NUM                     \
+    (65536 + FW_TUNNEL_NUM + FW_CTRL_NUM + FW_RI_NUM + FW_RX_PKT_NUM)
+
+/*
+ * FW type and version.
+ */
+#define S_FW_VERSION_TYPE              28
+#define M_FW_VERSION_TYPE              0xF
+#define V_FW_VERSION_TYPE(x)           ((x) << S_FW_VERSION_TYPE)
+#define G_FW_VERSION_TYPE(x)           \
+    (((x) >> S_FW_VERSION_TYPE) & M_FW_VERSION_TYPE)
+
+#define S_FW_VERSION_MAJOR             16
+#define M_FW_VERSION_MAJOR             0xFFF
+#define V_FW_VERSION_MAJOR(x)          ((x) << S_FW_VERSION_MAJOR)
+#define G_FW_VERSION_MAJOR(x)          \
+    (((x) >> S_FW_VERSION_MAJOR) & M_FW_VERSION_MAJOR)
+
+#define S_FW_VERSION_MINOR             8
+#define M_FW_VERSION_MINOR             0xFF
+#define V_FW_VERSION_MINOR(x)          ((x) << S_FW_VERSION_MINOR)
+#define G_FW_VERSION_MINOR(x)          \
+    (((x) >> S_FW_VERSION_MINOR) & M_FW_VERSION_MINOR)
+
+#define S_FW_VERSION_MICRO             0
+#define M_FW_VERSION_MICRO             0xFF
+#define V_FW_VERSION_MICRO(x)          ((x) << S_FW_VERSION_MICRO)
+#define G_FW_VERSION_MICRO(x)          \
+    (((x) >> S_FW_VERSION_MICRO) & M_FW_VERSION_MICRO)
+
+#endif                         /* _FIRMWARE_EXPORTS_H_ */
diff --git a/drivers/net/cxgb3/l2t.c b/drivers/net/cxgb3/l2t.c
new file mode 100644 (file)
index 0000000..3c0cb85
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/if.h>
+#include <linux/if_vlan.h>
+#include <linux/jhash.h>
+#include <net/neighbour.h>
+#include "common.h"
+#include "t3cdev.h"
+#include "cxgb3_defs.h"
+#include "l2t.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+#define VLAN_NONE 0xfff
+
+/*
+ * Module locking notes:  There is a RW lock protecting the L2 table as a
+ * whole plus a spinlock per L2T entry.  Entry lookups and allocations happen
+ * under the protection of the table lock, individual entry changes happen
+ * while holding that entry's spinlock.  The table lock nests outside the
+ * entry locks.  Allocations of new entries take the table lock as writers so
+ * no other lookups can happen while allocating new entries.  Entry updates
+ * take the table lock as readers so multiple entries can be updated in
+ * parallel.  An L2T entry can be dropped by decrementing its reference count
+ * and therefore can happen in parallel with entry allocation but no entry
+ * can change state or increment its ref count during allocation as both of
+ * these perform lookups.
+ */
+
+static inline unsigned int vlan_prio(const struct l2t_entry *e)
+{
+       return e->vlan >> 13;
+}
+
+static inline unsigned int arp_hash(u32 key, int ifindex,
+                                   const struct l2t_data *d)
+{
+       return jhash_2words(key, ifindex, 0) & (d->nentries - 1);
+}
+
+static inline void neigh_replace(struct l2t_entry *e, struct neighbour *n)
+{
+       neigh_hold(n);
+       if (e->neigh)
+               neigh_release(e->neigh);
+       e->neigh = n;
+}
+
+/*
+ * Set up an L2T entry and send any packets waiting in the arp queue.  The
+ * supplied skb is used for the CPL_L2T_WRITE_REQ.  Must be called with the
+ * entry locked.
+ */
+static int setup_l2e_send_pending(struct t3cdev *dev, struct sk_buff *skb,
+                                 struct l2t_entry *e)
+{
+       struct cpl_l2t_write_req *req;
+
+       if (!skb) {
+               skb = alloc_skb(sizeof(*req), GFP_ATOMIC);
+               if (!skb)
+                       return -ENOMEM;
+       }
+
+       req = (struct cpl_l2t_write_req *)__skb_put(skb, sizeof(*req));
+       req->wr.wr_hi = htonl(V_WR_OP(FW_WROPCODE_FORWARD));
+       OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ, e->idx));
+       req->params = htonl(V_L2T_W_IDX(e->idx) | V_L2T_W_IFF(e->smt_idx) |
+                           V_L2T_W_VLAN(e->vlan & VLAN_VID_MASK) |
+                           V_L2T_W_PRIO(vlan_prio(e)));
+       memcpy(e->dmac, e->neigh->ha, sizeof(e->dmac));
+       memcpy(req->dst_mac, e->dmac, sizeof(req->dst_mac));
+       skb->priority = CPL_PRIORITY_CONTROL;
+       cxgb3_ofld_send(dev, skb);
+       while (e->arpq_head) {
+               skb = e->arpq_head;
+               e->arpq_head = skb->next;
+               skb->next = NULL;
+               cxgb3_ofld_send(dev, skb);
+       }
+       e->arpq_tail = NULL;
+       e->state = L2T_STATE_VALID;
+
+       return 0;
+}
+
+/*
+ * Add a packet to the an L2T entry's queue of packets awaiting resolution.
+ * Must be called with the entry's lock held.
+ */
+static inline void arpq_enqueue(struct l2t_entry *e, struct sk_buff *skb)
+{
+       skb->next = NULL;
+       if (e->arpq_head)
+               e->arpq_tail->next = skb;
+       else
+               e->arpq_head = skb;
+       e->arpq_tail = skb;
+}
+
+int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb,
+                    struct l2t_entry *e)
+{
+again:
+       switch (e->state) {
+       case L2T_STATE_STALE:   /* entry is stale, kick off revalidation */
+               neigh_event_send(e->neigh, NULL);
+               spin_lock_bh(&e->lock);
+               if (e->state == L2T_STATE_STALE)
+                       e->state = L2T_STATE_VALID;
+               spin_unlock_bh(&e->lock);
+       case L2T_STATE_VALID:   /* fast-path, send the packet on */
+               return cxgb3_ofld_send(dev, skb);
+       case L2T_STATE_RESOLVING:
+               spin_lock_bh(&e->lock);
+               if (e->state != L2T_STATE_RESOLVING) {
+                       /* ARP already completed */
+                       spin_unlock_bh(&e->lock);
+                       goto again;
+               }
+               arpq_enqueue(e, skb);
+               spin_unlock_bh(&e->lock);
+
+               /*
+                * Only the first packet added to the arpq should kick off
+                * resolution.  However, because the alloc_skb below can fail,
+                * we allow each packet added to the arpq to retry resolution
+                * as a way of recovering from transient memory exhaustion.
+                * A better way would be to use a work request to retry L2T
+                * entries when there's no memory.
+                */
+               if (!neigh_event_send(e->neigh, NULL)) {
+                       skb = alloc_skb(sizeof(struct cpl_l2t_write_req),
+                                       GFP_ATOMIC);
+                       if (!skb)
+                               break;
+
+                       spin_lock_bh(&e->lock);
+                       if (e->arpq_head)
+                               setup_l2e_send_pending(dev, skb, e);
+                       else    /* we lost the race */
+                               __kfree_skb(skb);
+                       spin_unlock_bh(&e->lock);
+               }
+       }
+       return 0;
+}
+
+EXPORT_SYMBOL(t3_l2t_send_slow);
+
+void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e)
+{
+again:
+       switch (e->state) {
+       case L2T_STATE_STALE:   /* entry is stale, kick off revalidation */
+               neigh_event_send(e->neigh, NULL);
+               spin_lock_bh(&e->lock);
+               if (e->state == L2T_STATE_STALE) {
+                       e->state = L2T_STATE_VALID;
+               }
+               spin_unlock_bh(&e->lock);
+               return;
+       case L2T_STATE_VALID:   /* fast-path, send the packet on */
+               return;
+       case L2T_STATE_RESOLVING:
+               spin_lock_bh(&e->lock);
+               if (e->state != L2T_STATE_RESOLVING) {
+                       /* ARP already completed */
+                       spin_unlock_bh(&e->lock);
+                       goto again;
+               }
+               spin_unlock_bh(&e->lock);
+
+               /*
+                * Only the first packet added to the arpq should kick off
+                * resolution.  However, because the alloc_skb below can fail,
+                * we allow each packet added to the arpq to retry resolution
+                * as a way of recovering from transient memory exhaustion.
+                * A better way would be to use a work request to retry L2T
+                * entries when there's no memory.
+                */
+               neigh_event_send(e->neigh, NULL);
+       }
+       return;
+}
+
+EXPORT_SYMBOL(t3_l2t_send_event);
+
+/*
+ * Allocate a free L2T entry.  Must be called with l2t_data.lock held.
+ */
+static struct l2t_entry *alloc_l2e(struct l2t_data *d)
+{
+       struct l2t_entry *end, *e, **p;
+
+       if (!atomic_read(&d->nfree))
+               return NULL;
+
+       /* there's definitely a free entry */
+       for (e = d->rover, end = &d->l2tab[d->nentries]; e != end; ++e)
+               if (atomic_read(&e->refcnt) == 0)
+                       goto found;
+
+       for (e = &d->l2tab[1]; atomic_read(&e->refcnt); ++e) ;
+found:
+       d->rover = e + 1;
+       atomic_dec(&d->nfree);
+
+       /*
+        * The entry we found may be an inactive entry that is
+        * presently in the hash table.  We need to remove it.
+        */
+       if (e->state != L2T_STATE_UNUSED) {
+               int hash = arp_hash(e->addr, e->ifindex, d);
+
+               for (p = &d->l2tab[hash].first; *p; p = &(*p)->next)
+                       if (*p == e) {
+                               *p = e->next;
+                               break;
+                       }
+               e->state = L2T_STATE_UNUSED;
+       }
+       return e;
+}
+
+/*
+ * Called when an L2T entry has no more users.  The entry is left in the hash
+ * table since it is likely to be reused but we also bump nfree to indicate
+ * that the entry can be reallocated for a different neighbor.  We also drop
+ * the existing neighbor reference in case the neighbor is going away and is
+ * waiting on our reference.
+ *
+ * Because entries can be reallocated to other neighbors once their ref count
+ * drops to 0 we need to take the entry's lock to avoid races with a new
+ * incarnation.
+ */
+void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e)
+{
+       spin_lock_bh(&e->lock);
+       if (atomic_read(&e->refcnt) == 0) {     /* hasn't been recycled */
+               if (e->neigh) {
+                       neigh_release(e->neigh);
+                       e->neigh = NULL;
+               }
+       }
+       spin_unlock_bh(&e->lock);
+       atomic_inc(&d->nfree);
+}
+
+EXPORT_SYMBOL(t3_l2e_free);
+
+/*
+ * Update an L2T entry that was previously used for the same next hop as neigh.
+ * Must be called with softirqs disabled.
+ */
+static inline void reuse_entry(struct l2t_entry *e, struct neighbour *neigh)
+{
+       unsigned int nud_state;
+
+       spin_lock(&e->lock);    /* avoid race with t3_l2t_free */
+
+       if (neigh != e->neigh)
+               neigh_replace(e, neigh);
+       nud_state = neigh->nud_state;
+       if (memcmp(e->dmac, neigh->ha, sizeof(e->dmac)) ||
+           !(nud_state & NUD_VALID))
+               e->state = L2T_STATE_RESOLVING;
+       else if (nud_state & NUD_CONNECTED)
+               e->state = L2T_STATE_VALID;
+       else
+               e->state = L2T_STATE_STALE;
+       spin_unlock(&e->lock);
+}
+
+struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
+                            struct net_device *dev)
+{
+       struct l2t_entry *e;
+       struct l2t_data *d = L2DATA(cdev);
+       u32 addr = *(u32 *) neigh->primary_key;
+       int ifidx = neigh->dev->ifindex;
+       int hash = arp_hash(addr, ifidx, d);
+       struct port_info *p = netdev_priv(dev);
+       int smt_idx = p->port_id;
+
+       write_lock_bh(&d->lock);
+       for (e = d->l2tab[hash].first; e; e = e->next)
+               if (e->addr == addr && e->ifindex == ifidx &&
+                   e->smt_idx == smt_idx) {
+                       l2t_hold(d, e);
+                       if (atomic_read(&e->refcnt) == 1)
+                               reuse_entry(e, neigh);
+                       goto done;
+               }
+
+       /* Need to allocate a new entry */
+       e = alloc_l2e(d);
+       if (e) {
+               spin_lock(&e->lock);    /* avoid race with t3_l2t_free */
+               e->next = d->l2tab[hash].first;
+               d->l2tab[hash].first = e;
+               e->state = L2T_STATE_RESOLVING;
+               e->addr = addr;
+               e->ifindex = ifidx;
+               e->smt_idx = smt_idx;
+               atomic_set(&e->refcnt, 1);
+               neigh_replace(e, neigh);
+               if (neigh->dev->priv_flags & IFF_802_1Q_VLAN)
+                       e->vlan = VLAN_DEV_INFO(neigh->dev)->vlan_id;
+               else
+                       e->vlan = VLAN_NONE;
+               spin_unlock(&e->lock);
+       }
+done:
+       write_unlock_bh(&d->lock);
+       return e;
+}
+
+EXPORT_SYMBOL(t3_l2t_get);
+
+/*
+ * Called when address resolution fails for an L2T entry to handle packets
+ * on the arpq head.  If a packet specifies a failure handler it is invoked,
+ * otherwise the packets is sent to the offload device.
+ *
+ * XXX: maybe we should abandon the latter behavior and just require a failure
+ * handler.
+ */
+static void handle_failed_resolution(struct t3cdev *dev, struct sk_buff *arpq)
+{
+       while (arpq) {
+               struct sk_buff *skb = arpq;
+               struct l2t_skb_cb *cb = L2T_SKB_CB(skb);
+
+               arpq = skb->next;
+               skb->next = NULL;
+               if (cb->arp_failure_handler)
+                       cb->arp_failure_handler(dev, skb);
+               else
+                       cxgb3_ofld_send(dev, skb);
+       }
+}
+
+/*
+ * Called when the host's ARP layer makes a change to some entry that is
+ * loaded into the HW L2 table.
+ */
+void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh)
+{
+       struct l2t_entry *e;
+       struct sk_buff *arpq = NULL;
+       struct l2t_data *d = L2DATA(dev);
+       u32 addr = *(u32 *) neigh->primary_key;
+       int ifidx = neigh->dev->ifindex;
+       int hash = arp_hash(addr, ifidx, d);
+
+       read_lock_bh(&d->lock);
+       for (e = d->l2tab[hash].first; e; e = e->next)
+               if (e->addr == addr && e->ifindex == ifidx) {
+                       spin_lock(&e->lock);
+                       goto found;
+               }
+       read_unlock_bh(&d->lock);
+       return;
+
+found:
+       read_unlock(&d->lock);
+       if (atomic_read(&e->refcnt)) {
+               if (neigh != e->neigh)
+                       neigh_replace(e, neigh);
+
+               if (e->state == L2T_STATE_RESOLVING) {
+                       if (neigh->nud_state & NUD_FAILED) {
+                               arpq = e->arpq_head;
+                               e->arpq_head = e->arpq_tail = NULL;
+                       } else if (neigh_is_connected(neigh))
+                               setup_l2e_send_pending(dev, NULL, e);
+               } else {
+                       e->state = neigh_is_connected(neigh) ?
+                           L2T_STATE_VALID : L2T_STATE_STALE;
+                       if (memcmp(e->dmac, neigh->ha, 6))
+                               setup_l2e_send_pending(dev, NULL, e);
+               }
+       }
+       spin_unlock_bh(&e->lock);
+
+       if (arpq)
+               handle_failed_resolution(dev, arpq);
+}
+
+struct l2t_data *t3_init_l2t(unsigned int l2t_capacity)
+{
+       struct l2t_data *d;
+       int i, size = sizeof(*d) + l2t_capacity * sizeof(struct l2t_entry);
+
+       d = cxgb_alloc_mem(size);
+       if (!d)
+               return NULL;
+
+       d->nentries = l2t_capacity;
+       d->rover = &d->l2tab[1];        /* entry 0 is not used */
+       atomic_set(&d->nfree, l2t_capacity - 1);
+       rwlock_init(&d->lock);
+
+       for (i = 0; i < l2t_capacity; ++i) {
+               d->l2tab[i].idx = i;
+               d->l2tab[i].state = L2T_STATE_UNUSED;
+               spin_lock_init(&d->l2tab[i].lock);
+               atomic_set(&d->l2tab[i].refcnt, 0);
+       }
+       return d;
+}
+
+void t3_free_l2t(struct l2t_data *d)
+{
+       cxgb_free_mem(d);
+}
+
diff --git a/drivers/net/cxgb3/l2t.h b/drivers/net/cxgb3/l2t.h
new file mode 100644 (file)
index 0000000..ba5d2cb
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ * Copyright (c) 2006-2007 Open Grid Computing, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _CHELSIO_L2T_H
+#define _CHELSIO_L2T_H
+
+#include <linux/spinlock.h>
+#include "t3cdev.h"
+#include <asm/atomic.h>
+
+enum {
+       L2T_STATE_VALID,        /* entry is up to date */
+       L2T_STATE_STALE,        /* entry may be used but needs revalidation */
+       L2T_STATE_RESOLVING,    /* entry needs address resolution */
+       L2T_STATE_UNUSED        /* entry not in use */
+};
+
+struct neighbour;
+struct sk_buff;
+
+/*
+ * Each L2T entry plays multiple roles.  First of all, it keeps state for the
+ * corresponding entry of the HW L2 table and maintains a queue of offload
+ * packets awaiting address resolution.  Second, it is a node of a hash table
+ * chain, where the nodes of the chain are linked together through their next
+ * pointer.  Finally, each node is a bucket of a hash table, pointing to the
+ * first element in its chain through its first pointer.
+ */
+struct l2t_entry {
+       u16 state;              /* entry state */
+       u16 idx;                /* entry index */
+       u32 addr;               /* dest IP address */
+       int ifindex;            /* neighbor's net_device's ifindex */
+       u16 smt_idx;            /* SMT index */
+       u16 vlan;               /* VLAN TCI (id: bits 0-11, prio: 13-15 */
+       struct neighbour *neigh;        /* associated neighbour */
+       struct l2t_entry *first;        /* start of hash chain */
+       struct l2t_entry *next; /* next l2t_entry on chain */
+       struct sk_buff *arpq_head;      /* queue of packets awaiting resolution */
+       struct sk_buff *arpq_tail;
+       spinlock_t lock;
+       atomic_t refcnt;        /* entry reference count */
+       u8 dmac[6];             /* neighbour's MAC address */
+};
+
+struct l2t_data {
+       unsigned int nentries;  /* number of entries */
+       struct l2t_entry *rover;        /* starting point for next allocation */
+       atomic_t nfree;         /* number of free entries */
+       rwlock_t lock;
+       struct l2t_entry l2tab[0];
+};
+
+typedef void (*arp_failure_handler_func)(struct t3cdev * dev,
+                                        struct sk_buff * skb);
+
+/*
+ * Callback stored in an skb to handle address resolution failure.
+ */
+struct l2t_skb_cb {
+       arp_failure_handler_func arp_failure_handler;
+};
+
+#define L2T_SKB_CB(skb) ((struct l2t_skb_cb *)(skb)->cb)
+
+static inline void set_arp_failure_handler(struct sk_buff *skb,
+                                          arp_failure_handler_func hnd)
+{
+       L2T_SKB_CB(skb)->arp_failure_handler = hnd;
+}
+
+/*
+ * Getting to the L2 data from an offload device.
+ */
+#define L2DATA(dev) ((dev)->l2opt)
+
+#define W_TCB_L2T_IX    0
+#define S_TCB_L2T_IX    7
+#define M_TCB_L2T_IX    0x7ffULL
+#define V_TCB_L2T_IX(x) ((x) << S_TCB_L2T_IX)
+
+void t3_l2e_free(struct l2t_data *d, struct l2t_entry *e);
+void t3_l2t_update(struct t3cdev *dev, struct neighbour *neigh);
+struct l2t_entry *t3_l2t_get(struct t3cdev *cdev, struct neighbour *neigh,
+                            struct net_device *dev);
+int t3_l2t_send_slow(struct t3cdev *dev, struct sk_buff *skb,
+                    struct l2t_entry *e);
+void t3_l2t_send_event(struct t3cdev *dev, struct l2t_entry *e);
+struct l2t_data *t3_init_l2t(unsigned int l2t_capacity);
+void t3_free_l2t(struct l2t_data *d);
+
+int cxgb3_ofld_send(struct t3cdev *dev, struct sk_buff *skb);
+
+static inline int l2t_send(struct t3cdev *dev, struct sk_buff *skb,
+                          struct l2t_entry *e)
+{
+       if (likely(e->state == L2T_STATE_VALID))
+               return cxgb3_ofld_send(dev, skb);
+       return t3_l2t_send_slow(dev, skb, e);
+}
+
+static inline void l2t_release(struct l2t_data *d, struct l2t_entry *e)
+{
+       if (atomic_dec_and_test(&e->refcnt))
+               t3_l2e_free(d, e);
+}
+
+static inline void l2t_hold(struct l2t_data *d, struct l2t_entry *e)
+{
+       if (atomic_add_return(1, &e->refcnt) == 1)      /* 0 -> 1 transition */
+               atomic_dec(&d->nfree);
+}
+
+#endif
diff --git a/drivers/net/cxgb3/mc5.c b/drivers/net/cxgb3/mc5.c
new file mode 100644 (file)
index 0000000..644d62e
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+enum {
+       IDT75P52100 = 4,
+       IDT75N43102 = 5
+};
+
+/* DBGI command mode */
+enum {
+       DBGI_MODE_MBUS = 0,
+       DBGI_MODE_IDT52100 = 5
+};
+
+/* IDT 75P52100 commands */
+#define IDT_CMD_READ   0
+#define IDT_CMD_WRITE  1
+#define IDT_CMD_SEARCH 2
+#define IDT_CMD_LEARN  3
+
+/* IDT LAR register address and value for 144-bit mode (low 32 bits) */
+#define IDT_LAR_ADR0           0x180006
+#define IDT_LAR_MODE144        0xffff0000
+
+/* IDT SCR and SSR addresses (low 32 bits) */
+#define IDT_SCR_ADR0  0x180000
+#define IDT_SSR0_ADR0 0x180002
+#define IDT_SSR1_ADR0 0x180004
+
+/* IDT GMR base address (low 32 bits) */
+#define IDT_GMR_BASE_ADR0 0x180020
+
+/* IDT data and mask array base addresses (low 32 bits) */
+#define IDT_DATARY_BASE_ADR0 0
+#define IDT_MSKARY_BASE_ADR0 0x80000
+
+/* IDT 75N43102 commands */
+#define IDT4_CMD_SEARCH144 3
+#define IDT4_CMD_WRITE     4
+#define IDT4_CMD_READ      5
+
+/* IDT 75N43102 SCR address (low 32 bits) */
+#define IDT4_SCR_ADR0  0x3
+
+/* IDT 75N43102 GMR base addresses (low 32 bits) */
+#define IDT4_GMR_BASE0 0x10
+#define IDT4_GMR_BASE1 0x20
+#define IDT4_GMR_BASE2 0x30
+
+/* IDT 75N43102 data and mask array base addresses (low 32 bits) */
+#define IDT4_DATARY_BASE_ADR0 0x1000000
+#define IDT4_MSKARY_BASE_ADR0 0x2000000
+
+#define MAX_WRITE_ATTEMPTS 5
+
+#define MAX_ROUTES 2048
+
+/*
+ * Issue a command to the TCAM and wait for its completion.  The address and
+ * any data required by the command must have been setup by the caller.
+ */
+static int mc5_cmd_write(struct adapter *adapter, u32 cmd)
+{
+       t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_CMD, cmd);
+       return t3_wait_op_done(adapter, A_MC5_DB_DBGI_RSP_STATUS,
+                              F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1);
+}
+
+static inline void dbgi_wr_addr3(struct adapter *adapter, u32 v1, u32 v2,
+                                u32 v3)
+{
+       t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, v1);
+       t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR1, v2);
+       t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR2, v3);
+}
+
+static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2,
+                                u32 v3)
+{
+       t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA0, v1);
+       t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA1, v2);
+       t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3);
+}
+
+static inline void dbgi_rd_rsp3(struct adapter *adapter, u32 *v1, u32 *v2,
+                               u32 *v3)
+{
+       *v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0);
+       *v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1);
+       *v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2);
+}
+
+/*
+ * Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM
+ * command cmd.  The data to be written must have been set up by the caller.
+ * Returns -1 on failure, 0 on success.
+ */
+static int mc5_write(struct adapter *adapter, u32 addr_lo, u32 cmd)
+{
+       t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, addr_lo);
+       if (mc5_cmd_write(adapter, cmd) == 0)
+               return 0;
+       CH_ERR(adapter, "MC5 timeout writing to TCAM address 0x%x\n",
+              addr_lo);
+       return -1;
+}
+
+static int init_mask_data_array(struct mc5 *mc5, u32 mask_array_base,
+                               u32 data_array_base, u32 write_cmd,
+                               int addr_shift)
+{
+       unsigned int i;
+       struct adapter *adap = mc5->adapter;
+
+       /*
+        * We need the size of the TCAM data and mask arrays in terms of
+        * 72-bit entries.
+        */
+       unsigned int size72 = mc5->tcam_size;
+       unsigned int server_base = t3_read_reg(adap, A_MC5_DB_SERVER_INDEX);
+
+       if (mc5->mode == MC5_MODE_144_BIT) {
+               size72 *= 2;    /* 1 144-bit entry is 2 72-bit entries */
+               server_base *= 2;
+       }
+
+       /* Clear the data array */
+       dbgi_wr_data3(adap, 0, 0, 0);
+       for (i = 0; i < size72; i++)
+               if (mc5_write(adap, data_array_base + (i << addr_shift),
+                             write_cmd))
+                       return -1;
+
+       /* Initialize the mask array. */
+       dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+       for (i = 0; i < size72; i++) {
+               if (i == server_base)   /* entering server or routing region */
+                       t3_write_reg(adap, A_MC5_DB_DBGI_REQ_DATA0,
+                                    mc5->mode == MC5_MODE_144_BIT ?
+                                    0xfffffff9 : 0xfffffffd);
+               if (mc5_write(adap, mask_array_base + (i << addr_shift),
+                             write_cmd))
+                       return -1;
+       }
+       return 0;
+}
+
+static int init_idt52100(struct mc5 *mc5)
+{
+       int i;
+       struct adapter *adap = mc5->adapter;
+
+       t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
+                    V_RDLAT(0x15) | V_LRNLAT(0x15) | V_SRCHLAT(0x15));
+       t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 2);
+
+       /*
+        * Use GMRs 14-15 for ELOOKUP, GMRs 12-13 for SYN lookups, and
+        * GMRs 8-9 for ACK- and AOPEN searches.
+        */
+       t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT_CMD_WRITE);
+       t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT_CMD_WRITE);
+       t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD, IDT_CMD_SEARCH);
+       t3_write_reg(adap, A_MC5_DB_AOPEN_LRN_CMD, IDT_CMD_LEARN);
+       t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT_CMD_SEARCH | 0x6000);
+       t3_write_reg(adap, A_MC5_DB_SYN_LRN_CMD, IDT_CMD_LEARN);
+       t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT_CMD_SEARCH);
+       t3_write_reg(adap, A_MC5_DB_ACK_LRN_CMD, IDT_CMD_LEARN);
+       t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT_CMD_SEARCH);
+       t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT_CMD_SEARCH | 0x7000);
+       t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT_CMD_WRITE);
+       t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT_CMD_READ);
+
+       /* Set DBGI command mode for IDT TCAM. */
+       t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
+
+       /* Set up LAR */
+       dbgi_wr_data3(adap, IDT_LAR_MODE144, 0, 0);
+       if (mc5_write(adap, IDT_LAR_ADR0, IDT_CMD_WRITE))
+               goto err;
+
+       /* Set up SSRs */
+       dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0);
+       if (mc5_write(adap, IDT_SSR0_ADR0, IDT_CMD_WRITE) ||
+           mc5_write(adap, IDT_SSR1_ADR0, IDT_CMD_WRITE))
+               goto err;
+
+       /* Set up GMRs */
+       for (i = 0; i < 32; ++i) {
+               if (i >= 12 && i < 15)
+                       dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
+               else if (i == 15)
+                       dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
+               else
+                       dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+
+               if (mc5_write(adap, IDT_GMR_BASE_ADR0 + i, IDT_CMD_WRITE))
+                       goto err;
+       }
+
+       /* Set up SCR */
+       dbgi_wr_data3(adap, 1, 0, 0);
+       if (mc5_write(adap, IDT_SCR_ADR0, IDT_CMD_WRITE))
+               goto err;
+
+       return init_mask_data_array(mc5, IDT_MSKARY_BASE_ADR0,
+                                   IDT_DATARY_BASE_ADR0, IDT_CMD_WRITE, 0);
+err:
+       return -EIO;
+}
+
+static int init_idt43102(struct mc5 *mc5)
+{
+       int i;
+       struct adapter *adap = mc5->adapter;
+
+       t3_write_reg(adap, A_MC5_DB_RSP_LATENCY,
+                    adap->params.rev == 0 ? V_RDLAT(0xd) | V_SRCHLAT(0x11) :
+                    V_RDLAT(0xd) | V_SRCHLAT(0x12));
+
+       /*
+        * Use GMRs 24-25 for ELOOKUP, GMRs 20-21 for SYN lookups, and no mask
+        * for ACK- and AOPEN searches.
+        */
+       t3_write_reg(adap, A_MC5_DB_POPEN_DATA_WR_CMD, IDT4_CMD_WRITE);
+       t3_write_reg(adap, A_MC5_DB_POPEN_MASK_WR_CMD, IDT4_CMD_WRITE);
+       t3_write_reg(adap, A_MC5_DB_AOPEN_SRCH_CMD,
+                    IDT4_CMD_SEARCH144 | 0x3800);
+       t3_write_reg(adap, A_MC5_DB_SYN_SRCH_CMD, IDT4_CMD_SEARCH144);
+       t3_write_reg(adap, A_MC5_DB_ACK_SRCH_CMD, IDT4_CMD_SEARCH144 | 0x3800);
+       t3_write_reg(adap, A_MC5_DB_ILOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x3800);
+       t3_write_reg(adap, A_MC5_DB_ELOOKUP_CMD, IDT4_CMD_SEARCH144 | 0x800);
+       t3_write_reg(adap, A_MC5_DB_DATA_WRITE_CMD, IDT4_CMD_WRITE);
+       t3_write_reg(adap, A_MC5_DB_DATA_READ_CMD, IDT4_CMD_READ);
+
+       t3_write_reg(adap, A_MC5_DB_PART_ID_INDEX, 3);
+
+       /* Set DBGI command mode for IDT TCAM. */
+       t3_write_reg(adap, A_MC5_DB_DBGI_CONFIG, DBGI_MODE_IDT52100);
+
+       /* Set up GMRs */
+       dbgi_wr_data3(adap, 0xffffffff, 0xffffffff, 0xff);
+       for (i = 0; i < 7; ++i)
+               if (mc5_write(adap, IDT4_GMR_BASE0 + i, IDT4_CMD_WRITE))
+                       goto err;
+
+       for (i = 0; i < 4; ++i)
+               if (mc5_write(adap, IDT4_GMR_BASE2 + i, IDT4_CMD_WRITE))
+                       goto err;
+
+       dbgi_wr_data3(adap, 0xfffffff9, 0xffffffff, 0xff);
+       if (mc5_write(adap, IDT4_GMR_BASE1, IDT4_CMD_WRITE) ||
+           mc5_write(adap, IDT4_GMR_BASE1 + 1, IDT4_CMD_WRITE) ||
+           mc5_write(adap, IDT4_GMR_BASE1 + 4, IDT4_CMD_WRITE))
+               goto err;
+
+       dbgi_wr_data3(adap, 0xfffffff9, 0xffff8007, 0xff);
+       if (mc5_write(adap, IDT4_GMR_BASE1 + 5, IDT4_CMD_WRITE))
+               goto err;
+
+       /* Set up SCR */
+       dbgi_wr_data3(adap, 0xf0000000, 0, 0);
+       if (mc5_write(adap, IDT4_SCR_ADR0, IDT4_CMD_WRITE))
+               goto err;
+
+       return init_mask_data_array(mc5, IDT4_MSKARY_BASE_ADR0,
+                                   IDT4_DATARY_BASE_ADR0, IDT4_CMD_WRITE, 1);
+err:
+       return -EIO;
+}
+
+/* Put MC5 in DBGI mode. */
+static inline void mc5_dbgi_mode_enable(const struct mc5 *mc5)
+{
+       t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG,
+                    V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_DBGIEN);
+}
+
+/* Put MC5 in M-Bus mode. */
+static void mc5_dbgi_mode_disable(const struct mc5 *mc5)
+{
+       t3_write_reg(mc5->adapter, A_MC5_DB_CONFIG,
+                    V_TMMODE(mc5->mode == MC5_MODE_72_BIT) |
+                    V_COMPEN(mc5->mode == MC5_MODE_72_BIT) |
+                    V_PRTYEN(mc5->parity_enabled) | F_MBUSEN);
+}
+
+/*
+ * Initialization that requires the OS and protocol layers to already
+ * be intialized goes here.
+ */
+int t3_mc5_init(struct mc5 *mc5, unsigned int nservers, unsigned int nfilters,
+               unsigned int nroutes)
+{
+       u32 cfg;
+       int err;
+       unsigned int tcam_size = mc5->tcam_size;
+       struct adapter *adap = mc5->adapter;
+
+       if (nroutes > MAX_ROUTES || nroutes + nservers + nfilters > tcam_size)
+               return -EINVAL;
+
+       /* Reset the TCAM */
+       cfg = t3_read_reg(adap, A_MC5_DB_CONFIG) & ~F_TMMODE;
+       cfg |= V_TMMODE(mc5->mode == MC5_MODE_72_BIT) | F_TMRST;
+       t3_write_reg(adap, A_MC5_DB_CONFIG, cfg);
+       if (t3_wait_op_done(adap, A_MC5_DB_CONFIG, F_TMRDY, 1, 500, 0)) {
+               CH_ERR(adap, "TCAM reset timed out\n");
+               return -1;
+       }
+
+       t3_write_reg(adap, A_MC5_DB_ROUTING_TABLE_INDEX, tcam_size - nroutes);
+       t3_write_reg(adap, A_MC5_DB_FILTER_TABLE,
+                    tcam_size - nroutes - nfilters);
+       t3_write_reg(adap, A_MC5_DB_SERVER_INDEX,
+                    tcam_size - nroutes - nfilters - nservers);
+
+       mc5->parity_enabled = 1;
+
+       /* All the TCAM addresses we access have only the low 32 bits non 0 */
+       t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR1, 0);
+       t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR2, 0);
+
+       mc5_dbgi_mode_enable(mc5);
+
+       switch (mc5->part_type) {
+       case IDT75P52100:
+               err = init_idt52100(mc5);
+               break;
+       case IDT75N43102:
+               err = init_idt43102(mc5);
+               break;
+       default:
+               CH_ERR(adap, "Unsupported TCAM type %d\n", mc5->part_type);
+               err = -EINVAL;
+               break;
+       }
+
+       mc5_dbgi_mode_disable(mc5);
+       return err;
+}
+
+/*
+ *     read_mc5_range - dump a part of the memory managed by MC5
+ *     @mc5: the MC5 handle
+ *     @start: the start address for the dump
+ *     @n: number of 72-bit words to read
+ *     @buf: result buffer
+ *
+ *     Read n 72-bit words from MC5 memory from the given start location.
+ */
+int t3_read_mc5_range(const struct mc5 *mc5, unsigned int start,
+                     unsigned int n, u32 *buf)
+{
+       u32 read_cmd;
+       int err = 0;
+       struct adapter *adap = mc5->adapter;
+
+       if (mc5->part_type == IDT75P52100)
+               read_cmd = IDT_CMD_READ;
+       else if (mc5->part_type == IDT75N43102)
+               read_cmd = IDT4_CMD_READ;
+       else
+               return -EINVAL;
+
+       mc5_dbgi_mode_enable(mc5);
+
+       while (n--) {
+               t3_write_reg(adap, A_MC5_DB_DBGI_REQ_ADDR0, start++);
+               if (mc5_cmd_write(adap, read_cmd)) {
+                       err = -EIO;
+                       break;
+               }
+               dbgi_rd_rsp3(adap, buf + 2, buf + 1, buf);
+               buf += 3;
+       }
+
+       mc5_dbgi_mode_disable(mc5);
+       return 0;
+}
+
+#define MC5_INT_FATAL (F_PARITYERR | F_REQQPARERR | F_DISPQPARERR)
+
+/*
+ * MC5 interrupt handler
+ */
+void t3_mc5_intr_handler(struct mc5 *mc5)
+{
+       struct adapter *adap = mc5->adapter;
+       u32 cause = t3_read_reg(adap, A_MC5_DB_INT_CAUSE);
+
+       if ((cause & F_PARITYERR) && mc5->parity_enabled) {
+               CH_ALERT(adap, "MC5 parity error\n");
+               mc5->stats.parity_err++;
+       }
+
+       if (cause & F_REQQPARERR) {
+               CH_ALERT(adap, "MC5 request queue parity error\n");
+               mc5->stats.reqq_parity_err++;
+       }
+
+       if (cause & F_DISPQPARERR) {
+               CH_ALERT(adap, "MC5 dispatch queue parity error\n");
+               mc5->stats.dispq_parity_err++;
+       }
+
+       if (cause & F_ACTRGNFULL)
+               mc5->stats.active_rgn_full++;
+       if (cause & F_NFASRCHFAIL)
+               mc5->stats.nfa_srch_err++;
+       if (cause & F_UNKNOWNCMD)
+               mc5->stats.unknown_cmd++;
+       if (cause & F_DELACTEMPTY)
+               mc5->stats.del_act_empty++;
+       if (cause & MC5_INT_FATAL)
+               t3_fatal_err(adap);
+
+       t3_write_reg(adap, A_MC5_DB_INT_CAUSE, cause);
+}
+
+void __devinit t3_mc5_prep(struct adapter *adapter, struct mc5 *mc5, int mode)
+{
+#define K * 1024
+
+       static unsigned int tcam_part_size[] = {        /* in K 72-bit entries */
+               64 K, 128 K, 256 K, 32 K
+       };
+
+#undef K
+
+       u32 cfg = t3_read_reg(adapter, A_MC5_DB_CONFIG);
+
+       mc5->adapter = adapter;
+       mc5->mode = (unsigned char)mode;
+       mc5->part_type = (unsigned char)G_TMTYPE(cfg);
+       if (cfg & F_TMTYPEHI)
+               mc5->part_type |= 4;
+
+       mc5->tcam_size = tcam_part_size[G_TMPARTSIZE(cfg)];
+       if (mode == MC5_MODE_144_BIT)
+               mc5->tcam_size /= 2;
+}
diff --git a/drivers/net/cxgb3/regs.h b/drivers/net/cxgb3/regs.h
new file mode 100644 (file)
index 0000000..b56c5f5
--- /dev/null
@@ -0,0 +1,2195 @@
+#define A_SG_CONTROL 0x0
+
+#define S_DROPPKT    20
+#define V_DROPPKT(x) ((x) << S_DROPPKT)
+#define F_DROPPKT    V_DROPPKT(1U)
+
+#define S_EGRGENCTRL    19
+#define V_EGRGENCTRL(x) ((x) << S_EGRGENCTRL)
+#define F_EGRGENCTRL    V_EGRGENCTRL(1U)
+
+#define S_USERSPACESIZE    14
+#define M_USERSPACESIZE    0x1f
+#define V_USERSPACESIZE(x) ((x) << S_USERSPACESIZE)
+
+#define S_HOSTPAGESIZE    11
+#define M_HOSTPAGESIZE    0x7
+#define V_HOSTPAGESIZE(x) ((x) << S_HOSTPAGESIZE)
+
+#define S_FLMODE    9
+#define V_FLMODE(x) ((x) << S_FLMODE)
+#define F_FLMODE    V_FLMODE(1U)
+
+#define S_PKTSHIFT    6
+#define M_PKTSHIFT    0x7
+#define V_PKTSHIFT(x) ((x) << S_PKTSHIFT)
+
+#define S_ONEINTMULTQ    5
+#define V_ONEINTMULTQ(x) ((x) << S_ONEINTMULTQ)
+#define F_ONEINTMULTQ    V_ONEINTMULTQ(1U)
+
+#define S_BIGENDIANINGRESS    2
+#define V_BIGENDIANINGRESS(x) ((x) << S_BIGENDIANINGRESS)
+#define F_BIGENDIANINGRESS    V_BIGENDIANINGRESS(1U)
+
+#define S_ISCSICOALESCING    1
+#define V_ISCSICOALESCING(x) ((x) << S_ISCSICOALESCING)
+#define F_ISCSICOALESCING    V_ISCSICOALESCING(1U)
+
+#define S_GLOBALENABLE    0
+#define V_GLOBALENABLE(x) ((x) << S_GLOBALENABLE)
+#define F_GLOBALENABLE    V_GLOBALENABLE(1U)
+
+#define S_AVOIDCQOVFL    24
+#define V_AVOIDCQOVFL(x) ((x) << S_AVOIDCQOVFL)
+#define F_AVOIDCQOVFL    V_AVOIDCQOVFL(1U)
+
+#define S_OPTONEINTMULTQ    23
+#define V_OPTONEINTMULTQ(x) ((x) << S_OPTONEINTMULTQ)
+#define F_OPTONEINTMULTQ    V_OPTONEINTMULTQ(1U)
+
+#define S_CQCRDTCTRL    22
+#define V_CQCRDTCTRL(x) ((x) << S_CQCRDTCTRL)
+#define F_CQCRDTCTRL    V_CQCRDTCTRL(1U)
+
+#define A_SG_KDOORBELL 0x4
+
+#define S_SELEGRCNTX    31
+#define V_SELEGRCNTX(x) ((x) << S_SELEGRCNTX)
+#define F_SELEGRCNTX    V_SELEGRCNTX(1U)
+
+#define S_EGRCNTX    0
+#define M_EGRCNTX    0xffff
+#define V_EGRCNTX(x) ((x) << S_EGRCNTX)
+
+#define A_SG_GTS 0x8
+
+#define S_RSPQ    29
+#define M_RSPQ    0x7
+#define V_RSPQ(x) ((x) << S_RSPQ)
+#define G_RSPQ(x) (((x) >> S_RSPQ) & M_RSPQ)
+
+#define S_NEWTIMER    16
+#define M_NEWTIMER    0x1fff
+#define V_NEWTIMER(x) ((x) << S_NEWTIMER)
+
+#define S_NEWINDEX    0
+#define M_NEWINDEX    0xffff
+#define V_NEWINDEX(x) ((x) << S_NEWINDEX)
+
+#define A_SG_CONTEXT_CMD 0xc
+
+#define S_CONTEXT_CMD_OPCODE    28
+#define M_CONTEXT_CMD_OPCODE    0xf
+#define V_CONTEXT_CMD_OPCODE(x) ((x) << S_CONTEXT_CMD_OPCODE)
+
+#define S_CONTEXT_CMD_BUSY    27
+#define V_CONTEXT_CMD_BUSY(x) ((x) << S_CONTEXT_CMD_BUSY)
+#define F_CONTEXT_CMD_BUSY    V_CONTEXT_CMD_BUSY(1U)
+
+#define S_CQ_CREDIT    20
+
+#define M_CQ_CREDIT    0x7f
+
+#define V_CQ_CREDIT(x) ((x) << S_CQ_CREDIT)
+
+#define G_CQ_CREDIT(x) (((x) >> S_CQ_CREDIT) & M_CQ_CREDIT)
+
+#define S_CQ    19
+
+#define V_CQ(x) ((x) << S_CQ)
+#define F_CQ    V_CQ(1U)
+
+#define S_RESPONSEQ    18
+#define V_RESPONSEQ(x) ((x) << S_RESPONSEQ)
+#define F_RESPONSEQ    V_RESPONSEQ(1U)
+
+#define S_EGRESS    17
+#define V_EGRESS(x) ((x) << S_EGRESS)
+#define F_EGRESS    V_EGRESS(1U)
+
+#define S_FREELIST    16
+#define V_FREELIST(x) ((x) << S_FREELIST)
+#define F_FREELIST    V_FREELIST(1U)
+
+#define S_CONTEXT    0
+#define M_CONTEXT    0xffff
+#define V_CONTEXT(x) ((x) << S_CONTEXT)
+
+#define G_CONTEXT(x) (((x) >> S_CONTEXT) & M_CONTEXT)
+
+#define A_SG_CONTEXT_DATA0 0x10
+
+#define A_SG_CONTEXT_DATA1 0x14
+
+#define A_SG_CONTEXT_DATA2 0x18
+
+#define A_SG_CONTEXT_DATA3 0x1c
+
+#define A_SG_CONTEXT_MASK0 0x20
+
+#define A_SG_CONTEXT_MASK1 0x24
+
+#define A_SG_CONTEXT_MASK2 0x28
+
+#define A_SG_CONTEXT_MASK3 0x2c
+
+#define A_SG_RSPQ_CREDIT_RETURN 0x30
+
+#define S_CREDITS    0
+#define M_CREDITS    0xffff
+#define V_CREDITS(x) ((x) << S_CREDITS)
+
+#define A_SG_DATA_INTR 0x34
+
+#define S_ERRINTR    31
+#define V_ERRINTR(x) ((x) << S_ERRINTR)
+#define F_ERRINTR    V_ERRINTR(1U)
+
+#define A_SG_HI_DRB_HI_THRSH 0x38
+
+#define A_SG_HI_DRB_LO_THRSH 0x3c
+
+#define A_SG_LO_DRB_HI_THRSH 0x40
+
+#define A_SG_LO_DRB_LO_THRSH 0x44
+
+#define A_SG_RSPQ_FL_STATUS 0x4c
+
+#define S_RSPQ0DISABLED    8
+
+#define A_SG_EGR_RCQ_DRB_THRSH 0x54
+
+#define S_HIRCQDRBTHRSH    16
+#define M_HIRCQDRBTHRSH    0x7ff
+#define V_HIRCQDRBTHRSH(x) ((x) << S_HIRCQDRBTHRSH)
+
+#define S_LORCQDRBTHRSH    0
+#define M_LORCQDRBTHRSH    0x7ff
+#define V_LORCQDRBTHRSH(x) ((x) << S_LORCQDRBTHRSH)
+
+#define A_SG_EGR_CNTX_BADDR 0x58
+
+#define A_SG_INT_CAUSE 0x5c
+
+#define S_RSPQDISABLED    3
+#define V_RSPQDISABLED(x) ((x) << S_RSPQDISABLED)
+#define F_RSPQDISABLED    V_RSPQDISABLED(1U)
+
+#define S_RSPQCREDITOVERFOW    2
+#define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW)
+#define F_RSPQCREDITOVERFOW    V_RSPQCREDITOVERFOW(1U)
+
+#define A_SG_INT_ENABLE 0x60
+
+#define A_SG_CMDQ_CREDIT_TH 0x64
+
+#define S_TIMEOUT    8
+#define M_TIMEOUT    0xffffff
+#define V_TIMEOUT(x) ((x) << S_TIMEOUT)
+
+#define S_THRESHOLD    0
+#define M_THRESHOLD    0xff
+#define V_THRESHOLD(x) ((x) << S_THRESHOLD)
+
+#define A_SG_TIMER_TICK 0x68
+
+#define A_SG_CQ_CONTEXT_BADDR 0x6c
+
+#define A_SG_OCO_BASE 0x70
+
+#define S_BASE1    16
+#define M_BASE1    0xffff
+#define V_BASE1(x) ((x) << S_BASE1)
+
+#define A_SG_DRB_PRI_THRESH 0x74
+
+#define A_PCIX_INT_ENABLE 0x80
+
+#define S_MSIXPARERR    22
+#define M_MSIXPARERR    0x7
+
+#define V_MSIXPARERR(x) ((x) << S_MSIXPARERR)
+
+#define S_CFPARERR    18
+#define M_CFPARERR    0xf
+
+#define V_CFPARERR(x) ((x) << S_CFPARERR)
+
+#define S_RFPARERR    14
+#define M_RFPARERR    0xf
+
+#define V_RFPARERR(x) ((x) << S_RFPARERR)
+
+#define S_WFPARERR    12
+#define M_WFPARERR    0x3
+
+#define V_WFPARERR(x) ((x) << S_WFPARERR)
+
+#define S_PIOPARERR    11
+#define V_PIOPARERR(x) ((x) << S_PIOPARERR)
+#define F_PIOPARERR    V_PIOPARERR(1U)
+
+#define S_DETUNCECCERR    10
+#define V_DETUNCECCERR(x) ((x) << S_DETUNCECCERR)
+#define F_DETUNCECCERR    V_DETUNCECCERR(1U)
+
+#define S_DETCORECCERR    9
+#define V_DETCORECCERR(x) ((x) << S_DETCORECCERR)
+#define F_DETCORECCERR    V_DETCORECCERR(1U)
+
+#define S_RCVSPLCMPERR    8
+#define V_RCVSPLCMPERR(x) ((x) << S_RCVSPLCMPERR)
+#define F_RCVSPLCMPERR    V_RCVSPLCMPERR(1U)
+
+#define S_UNXSPLCMP    7
+#define V_UNXSPLCMP(x) ((x) << S_UNXSPLCMP)
+#define F_UNXSPLCMP    V_UNXSPLCMP(1U)
+
+#define S_SPLCMPDIS    6
+#define V_SPLCMPDIS(x) ((x) << S_SPLCMPDIS)
+#define F_SPLCMPDIS    V_SPLCMPDIS(1U)
+
+#define S_DETPARERR    5
+#define V_DETPARERR(x) ((x) << S_DETPARERR)
+#define F_DETPARERR    V_DETPARERR(1U)
+
+#define S_SIGSYSERR    4
+#define V_SIGSYSERR(x) ((x) << S_SIGSYSERR)
+#define F_SIGSYSERR    V_SIGSYSERR(1U)
+
+#define S_RCVMSTABT    3
+#define V_RCVMSTABT(x) ((x) << S_RCVMSTABT)
+#define F_RCVMSTABT    V_RCVMSTABT(1U)
+
+#define S_RCVTARABT    2
+#define V_RCVTARABT(x) ((x) << S_RCVTARABT)
+#define F_RCVTARABT    V_RCVTARABT(1U)
+
+#define S_SIGTARABT    1
+#define V_SIGTARABT(x) ((x) << S_SIGTARABT)
+#define F_SIGTARABT    V_SIGTARABT(1U)
+
+#define S_MSTDETPARERR    0
+#define V_MSTDETPARERR(x) ((x) << S_MSTDETPARERR)
+#define F_MSTDETPARERR    V_MSTDETPARERR(1U)
+
+#define A_PCIX_INT_CAUSE 0x84
+
+#define A_PCIX_CFG 0x88
+
+#define S_CLIDECEN    18
+#define V_CLIDECEN(x) ((x) << S_CLIDECEN)
+#define F_CLIDECEN    V_CLIDECEN(1U)
+
+#define A_PCIX_MODE 0x8c
+
+#define S_PCLKRANGE    6
+#define M_PCLKRANGE    0x3
+#define V_PCLKRANGE(x) ((x) << S_PCLKRANGE)
+#define G_PCLKRANGE(x) (((x) >> S_PCLKRANGE) & M_PCLKRANGE)
+
+#define S_PCIXINITPAT    2
+#define M_PCIXINITPAT    0xf
+#define V_PCIXINITPAT(x) ((x) << S_PCIXINITPAT)
+#define G_PCIXINITPAT(x) (((x) >> S_PCIXINITPAT) & M_PCIXINITPAT)
+
+#define S_64BIT    0
+#define V_64BIT(x) ((x) << S_64BIT)
+#define F_64BIT    V_64BIT(1U)
+
+#define A_PCIE_INT_ENABLE 0x80
+
+#define S_BISTERR    15
+#define M_BISTERR    0xff
+
+#define V_BISTERR(x) ((x) << S_BISTERR)
+
+#define S_PCIE_MSIXPARERR    12
+#define M_PCIE_MSIXPARERR    0x7
+
+#define V_PCIE_MSIXPARERR(x) ((x) << S_PCIE_MSIXPARERR)
+
+#define S_PCIE_CFPARERR    11
+#define V_PCIE_CFPARERR(x) ((x) << S_PCIE_CFPARERR)
+#define F_PCIE_CFPARERR    V_PCIE_CFPARERR(1U)
+
+#define S_PCIE_RFPARERR    10
+#define V_PCIE_RFPARERR(x) ((x) << S_PCIE_RFPARERR)
+#define F_PCIE_RFPARERR    V_PCIE_RFPARERR(1U)
+
+#define S_PCIE_WFPARERR    9
+#define V_PCIE_WFPARERR(x) ((x) << S_PCIE_WFPARERR)
+#define F_PCIE_WFPARERR    V_PCIE_WFPARERR(1U)
+
+#define S_PCIE_PIOPARERR    8
+#define V_PCIE_PIOPARERR(x) ((x) << S_PCIE_PIOPARERR)
+#define F_PCIE_PIOPARERR    V_PCIE_PIOPARERR(1U)
+
+#define S_UNXSPLCPLERRC    7
+#define V_UNXSPLCPLERRC(x) ((x) << S_UNXSPLCPLERRC)
+#define F_UNXSPLCPLERRC    V_UNXSPLCPLERRC(1U)
+
+#define S_UNXSPLCPLERRR    6
+#define V_UNXSPLCPLERRR(x) ((x) << S_UNXSPLCPLERRR)
+#define F_UNXSPLCPLERRR    V_UNXSPLCPLERRR(1U)
+
+#define S_PEXERR    0
+#define V_PEXERR(x) ((x) << S_PEXERR)
+#define F_PEXERR    V_PEXERR(1U)
+
+#define A_PCIE_INT_CAUSE 0x84
+
+#define A_PCIE_CFG 0x88
+
+#define S_PCIE_CLIDECEN    16
+#define V_PCIE_CLIDECEN(x) ((x) << S_PCIE_CLIDECEN)
+#define F_PCIE_CLIDECEN    V_PCIE_CLIDECEN(1U)
+
+#define S_CRSTWRMMODE    0
+#define V_CRSTWRMMODE(x) ((x) << S_CRSTWRMMODE)
+#define F_CRSTWRMMODE    V_CRSTWRMMODE(1U)
+
+#define A_PCIE_MODE 0x8c
+
+#define S_NUMFSTTRNSEQRX    10
+#define M_NUMFSTTRNSEQRX    0xff
+#define V_NUMFSTTRNSEQRX(x) ((x) << S_NUMFSTTRNSEQRX)
+#define G_NUMFSTTRNSEQRX(x) (((x) >> S_NUMFSTTRNSEQRX) & M_NUMFSTTRNSEQRX)
+
+#define A_PCIE_PEX_CTRL0 0x98
+
+#define S_NUMFSTTRNSEQ    22
+#define M_NUMFSTTRNSEQ    0xff
+#define V_NUMFSTTRNSEQ(x) ((x) << S_NUMFSTTRNSEQ)
+#define G_NUMFSTTRNSEQ(x) (((x) >> S_NUMFSTTRNSEQ) & M_NUMFSTTRNSEQ)
+
+#define S_REPLAYLMT    2
+#define M_REPLAYLMT    0xfffff
+
+#define V_REPLAYLMT(x) ((x) << S_REPLAYLMT)
+
+#define A_PCIE_PEX_CTRL1 0x9c
+
+#define S_T3A_ACKLAT    0
+#define M_T3A_ACKLAT    0x7ff
+
+#define V_T3A_ACKLAT(x) ((x) << S_T3A_ACKLAT)
+
+#define S_ACKLAT    0
+#define M_ACKLAT    0x1fff
+
+#define V_ACKLAT(x) ((x) << S_ACKLAT)
+
+#define A_PCIE_PEX_ERR 0xa4
+
+#define A_T3DBG_GPIO_EN 0xd0
+
+#define S_GPIO11_OEN    27
+#define V_GPIO11_OEN(x) ((x) << S_GPIO11_OEN)
+#define F_GPIO11_OEN    V_GPIO11_OEN(1U)
+
+#define S_GPIO10_OEN    26
+#define V_GPIO10_OEN(x) ((x) << S_GPIO10_OEN)
+#define F_GPIO10_OEN    V_GPIO10_OEN(1U)
+
+#define S_GPIO7_OEN    23
+#define V_GPIO7_OEN(x) ((x) << S_GPIO7_OEN)
+#define F_GPIO7_OEN    V_GPIO7_OEN(1U)
+
+#define S_GPIO6_OEN    22
+#define V_GPIO6_OEN(x) ((x) << S_GPIO6_OEN)
+#define F_GPIO6_OEN    V_GPIO6_OEN(1U)
+
+#define S_GPIO5_OEN    21
+#define V_GPIO5_OEN(x) ((x) << S_GPIO5_OEN)
+#define F_GPIO5_OEN    V_GPIO5_OEN(1U)
+
+#define S_GPIO4_OEN    20
+#define V_GPIO4_OEN(x) ((x) << S_GPIO4_OEN)
+#define F_GPIO4_OEN    V_GPIO4_OEN(1U)
+
+#define S_GPIO2_OEN    18
+#define V_GPIO2_OEN(x) ((x) << S_GPIO2_OEN)
+#define F_GPIO2_OEN    V_GPIO2_OEN(1U)
+
+#define S_GPIO1_OEN    17
+#define V_GPIO1_OEN(x) ((x) << S_GPIO1_OEN)
+#define F_GPIO1_OEN    V_GPIO1_OEN(1U)
+
+#define S_GPIO0_OEN    16
+#define V_GPIO0_OEN(x) ((x) << S_GPIO0_OEN)
+#define F_GPIO0_OEN    V_GPIO0_OEN(1U)
+
+#define S_GPIO10_OUT_VAL    10
+#define V_GPIO10_OUT_VAL(x) ((x) << S_GPIO10_OUT_VAL)
+#define F_GPIO10_OUT_VAL    V_GPIO10_OUT_VAL(1U)
+
+#define S_GPIO7_OUT_VAL    7
+#define V_GPIO7_OUT_VAL(x) ((x) << S_GPIO7_OUT_VAL)
+#define F_GPIO7_OUT_VAL    V_GPIO7_OUT_VAL(1U)
+
+#define S_GPIO6_OUT_VAL    6
+#define V_GPIO6_OUT_VAL(x) ((x) << S_GPIO6_OUT_VAL)
+#define F_GPIO6_OUT_VAL    V_GPIO6_OUT_VAL(1U)
+
+#define S_GPIO5_OUT_VAL    5
+#define V_GPIO5_OUT_VAL(x) ((x) << S_GPIO5_OUT_VAL)
+#define F_GPIO5_OUT_VAL    V_GPIO5_OUT_VAL(1U)
+
+#define S_GPIO4_OUT_VAL    4
+#define V_GPIO4_OUT_VAL(x) ((x) << S_GPIO4_OUT_VAL)
+#define F_GPIO4_OUT_VAL    V_GPIO4_OUT_VAL(1U)
+
+#define S_GPIO2_OUT_VAL    2
+#define V_GPIO2_OUT_VAL(x) ((x) << S_GPIO2_OUT_VAL)
+#define F_GPIO2_OUT_VAL    V_GPIO2_OUT_VAL(1U)
+
+#define S_GPIO1_OUT_VAL    1
+#define V_GPIO1_OUT_VAL(x) ((x) << S_GPIO1_OUT_VAL)
+#define F_GPIO1_OUT_VAL    V_GPIO1_OUT_VAL(1U)
+
+#define S_GPIO0_OUT_VAL    0
+#define V_GPIO0_OUT_VAL(x) ((x) << S_GPIO0_OUT_VAL)
+#define F_GPIO0_OUT_VAL    V_GPIO0_OUT_VAL(1U)
+
+#define A_T3DBG_INT_ENABLE 0xd8
+
+#define S_GPIO11    11
+#define V_GPIO11(x) ((x) << S_GPIO11)
+#define F_GPIO11    V_GPIO11(1U)
+
+#define S_GPIO10    10
+#define V_GPIO10(x) ((x) << S_GPIO10)
+#define F_GPIO10    V_GPIO10(1U)
+
+#define S_GPIO7    7
+#define V_GPIO7(x) ((x) << S_GPIO7)
+#define F_GPIO7    V_GPIO7(1U)
+
+#define S_GPIO6    6
+#define V_GPIO6(x) ((x) << S_GPIO6)
+#define F_GPIO6    V_GPIO6(1U)
+
+#define S_GPIO5    5
+#define V_GPIO5(x) ((x) << S_GPIO5)
+#define F_GPIO5    V_GPIO5(1U)
+
+#define S_GPIO4    4
+#define V_GPIO4(x) ((x) << S_GPIO4)
+#define F_GPIO4    V_GPIO4(1U)
+
+#define S_GPIO3    3
+#define V_GPIO3(x) ((x) << S_GPIO3)
+#define F_GPIO3    V_GPIO3(1U)
+
+#define S_GPIO2    2
+#define V_GPIO2(x) ((x) << S_GPIO2)
+#define F_GPIO2    V_GPIO2(1U)
+
+#define S_GPIO1    1
+#define V_GPIO1(x) ((x) << S_GPIO1)
+#define F_GPIO1    V_GPIO1(1U)
+
+#define S_GPIO0    0
+#define V_GPIO0(x) ((x) << S_GPIO0)
+#define F_GPIO0    V_GPIO0(1U)
+
+#define A_T3DBG_INT_CAUSE 0xdc
+
+#define A_T3DBG_GPIO_ACT_LOW 0xf0
+
+#define MC7_PMRX_BASE_ADDR 0x100
+
+#define A_MC7_CFG 0x100
+
+#define S_IFEN    13
+#define V_IFEN(x) ((x) << S_IFEN)
+#define F_IFEN    V_IFEN(1U)
+
+#define S_TERM150    11
+#define V_TERM150(x) ((x) << S_TERM150)
+#define F_TERM150    V_TERM150(1U)
+
+#define S_SLOW    10
+#define V_SLOW(x) ((x) << S_SLOW)
+#define F_SLOW    V_SLOW(1U)
+
+#define S_WIDTH    8
+#define M_WIDTH    0x3
+#define V_WIDTH(x) ((x) << S_WIDTH)
+#define G_WIDTH(x) (((x) >> S_WIDTH) & M_WIDTH)
+
+#define S_BKS    6
+#define V_BKS(x) ((x) << S_BKS)
+#define F_BKS    V_BKS(1U)
+
+#define S_ORG    5
+#define V_ORG(x) ((x) << S_ORG)
+#define F_ORG    V_ORG(1U)
+
+#define S_DEN    2
+#define M_DEN    0x7
+#define V_DEN(x) ((x) << S_DEN)
+#define G_DEN(x) (((x) >> S_DEN) & M_DEN)
+
+#define S_RDY    1
+#define V_RDY(x) ((x) << S_RDY)
+#define F_RDY    V_RDY(1U)
+
+#define S_CLKEN    0
+#define V_CLKEN(x) ((x) << S_CLKEN)
+#define F_CLKEN    V_CLKEN(1U)
+
+#define A_MC7_MODE 0x104
+
+#define S_BUSY    31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY    V_BUSY(1U)
+
+#define S_BUSY    31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY    V_BUSY(1U)
+
+#define A_MC7_EXT_MODE1 0x108
+
+#define A_MC7_EXT_MODE2 0x10c
+
+#define A_MC7_EXT_MODE3 0x110
+
+#define A_MC7_PRE 0x114
+
+#define A_MC7_REF 0x118
+
+#define S_PREREFDIV    1
+#define M_PREREFDIV    0x3fff
+#define V_PREREFDIV(x) ((x) << S_PREREFDIV)
+
+#define S_PERREFEN    0
+#define V_PERREFEN(x) ((x) << S_PERREFEN)
+#define F_PERREFEN    V_PERREFEN(1U)
+
+#define A_MC7_DLL 0x11c
+
+#define S_DLLENB    1
+#define V_DLLENB(x) ((x) << S_DLLENB)
+#define F_DLLENB    V_DLLENB(1U)
+
+#define S_DLLRST    0
+#define V_DLLRST(x) ((x) << S_DLLRST)
+#define F_DLLRST    V_DLLRST(1U)
+
+#define A_MC7_PARM 0x120
+
+#define S_ACTTOPREDLY    26
+#define M_ACTTOPREDLY    0xf
+#define V_ACTTOPREDLY(x) ((x) << S_ACTTOPREDLY)
+
+#define S_ACTTORDWRDLY    23
+#define M_ACTTORDWRDLY    0x7
+#define V_ACTTORDWRDLY(x) ((x) << S_ACTTORDWRDLY)
+
+#define S_PRECYC    20
+#define M_PRECYC    0x7
+#define V_PRECYC(x) ((x) << S_PRECYC)
+
+#define S_REFCYC    13
+#define M_REFCYC    0x7f
+#define V_REFCYC(x) ((x) << S_REFCYC)
+
+#define S_BKCYC    8
+#define M_BKCYC    0x1f
+#define V_BKCYC(x) ((x) << S_BKCYC)
+
+#define S_WRTORDDLY    4
+#define M_WRTORDDLY    0xf
+#define V_WRTORDDLY(x) ((x) << S_WRTORDDLY)
+
+#define S_RDTOWRDLY    0
+#define M_RDTOWRDLY    0xf
+#define V_RDTOWRDLY(x) ((x) << S_RDTOWRDLY)
+
+#define A_MC7_CAL 0x128
+
+#define S_BUSY    31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY    V_BUSY(1U)
+
+#define S_BUSY    31
+#define V_BUSY(x) ((x) << S_BUSY)
+#define F_BUSY    V_BUSY(1U)
+
+#define S_CAL_FAULT    30
+#define V_CAL_FAULT(x) ((x) << S_CAL_FAULT)
+#define F_CAL_FAULT    V_CAL_FAULT(1U)
+
+#define S_SGL_CAL_EN    20
+#define V_SGL_CAL_EN(x) ((x) << S_SGL_CAL_EN)
+#define F_SGL_CAL_EN    V_SGL_CAL_EN(1U)
+
+#define A_MC7_ERR_ADDR 0x12c
+
+#define A_MC7_ECC 0x130
+
+#define S_ECCCHKEN    1
+#define V_ECCCHKEN(x) ((x) << S_ECCCHKEN)
+#define F_ECCCHKEN    V_ECCCHKEN(1U)
+
+#define S_ECCGENEN    0
+#define V_ECCGENEN(x) ((x) << S_ECCGENEN)
+#define F_ECCGENEN    V_ECCGENEN(1U)
+
+#define A_MC7_CE_ADDR 0x134
+
+#define A_MC7_CE_DATA0 0x138
+
+#define A_MC7_CE_DATA1 0x13c
+
+#define A_MC7_CE_DATA2 0x140
+
+#define S_DATA    0
+#define M_DATA    0xff
+
+#define G_DATA(x) (((x) >> S_DATA) & M_DATA)
+
+#define A_MC7_UE_ADDR 0x144
+
+#define A_MC7_UE_DATA0 0x148
+
+#define A_MC7_UE_DATA1 0x14c
+
+#define A_MC7_UE_DATA2 0x150
+
+#define A_MC7_BD_ADDR 0x154
+
+#define S_ADDR    3
+
+#define M_ADDR    0x1fffffff
+
+#define A_MC7_BD_DATA0 0x158
+
+#define A_MC7_BD_DATA1 0x15c
+
+#define A_MC7_BD_OP 0x164
+
+#define S_OP    0
+
+#define V_OP(x) ((x) << S_OP)
+#define F_OP    V_OP(1U)
+
+#define F_OP    V_OP(1U)
+#define A_SF_OP 0x6dc
+
+#define A_MC7_BIST_ADDR_BEG 0x168
+
+#define A_MC7_BIST_ADDR_END 0x16c
+
+#define A_MC7_BIST_DATA 0x170
+
+#define A_MC7_BIST_OP 0x174
+
+#define S_CONT    3
+#define V_CONT(x) ((x) << S_CONT)
+#define F_CONT    V_CONT(1U)
+
+#define F_CONT    V_CONT(1U)
+
+#define A_MC7_INT_ENABLE 0x178
+
+#define S_AE    17
+#define V_AE(x) ((x) << S_AE)
+#define F_AE    V_AE(1U)
+
+#define S_PE    2
+#define M_PE    0x7fff
+
+#define V_PE(x) ((x) << S_PE)
+
+#define G_PE(x) (((x) >> S_PE) & M_PE)
+
+#define S_UE    1
+#define V_UE(x) ((x) << S_UE)
+#define F_UE    V_UE(1U)
+
+#define S_CE    0
+#define V_CE(x) ((x) << S_CE)
+#define F_CE    V_CE(1U)
+
+#define A_MC7_INT_CAUSE 0x17c
+
+#define MC7_PMTX_BASE_ADDR 0x180
+
+#define MC7_CM_BASE_ADDR 0x200
+
+#define A_CIM_BOOT_CFG 0x280
+
+#define S_BOOTADDR    2
+#define M_BOOTADDR    0x3fffffff
+#define V_BOOTADDR(x) ((x) << S_BOOTADDR)
+
+#define A_CIM_SDRAM_BASE_ADDR 0x28c
+
+#define A_CIM_SDRAM_ADDR_SIZE 0x290
+
+#define A_CIM_HOST_INT_ENABLE 0x298
+
+#define A_CIM_HOST_INT_CAUSE 0x29c
+
+#define S_BLKWRPLINT    12
+#define V_BLKWRPLINT(x) ((x) << S_BLKWRPLINT)
+#define F_BLKWRPLINT    V_BLKWRPLINT(1U)
+
+#define S_BLKRDPLINT    11
+#define V_BLKRDPLINT(x) ((x) << S_BLKRDPLINT)
+#define F_BLKRDPLINT    V_BLKRDPLINT(1U)
+
+#define S_BLKWRCTLINT    10
+#define V_BLKWRCTLINT(x) ((x) << S_BLKWRCTLINT)
+#define F_BLKWRCTLINT    V_BLKWRCTLINT(1U)
+
+#define S_BLKRDCTLINT    9
+#define V_BLKRDCTLINT(x) ((x) << S_BLKRDCTLINT)
+#define F_BLKRDCTLINT    V_BLKRDCTLINT(1U)
+
+#define S_BLKWRFLASHINT    8
+#define V_BLKWRFLASHINT(x) ((x) << S_BLKWRFLASHINT)
+#define F_BLKWRFLASHINT    V_BLKWRFLASHINT(1U)
+
+#define S_BLKRDFLASHINT    7
+#define V_BLKRDFLASHINT(x) ((x) << S_BLKRDFLASHINT)
+#define F_BLKRDFLASHINT    V_BLKRDFLASHINT(1U)
+
+#define S_SGLWRFLASHINT    6
+#define V_SGLWRFLASHINT(x) ((x) << S_SGLWRFLASHINT)
+#define F_SGLWRFLASHINT    V_SGLWRFLASHINT(1U)
+
+#define S_WRBLKFLASHINT    5
+#define V_WRBLKFLASHINT(x) ((x) << S_WRBLKFLASHINT)
+#define F_WRBLKFLASHINT    V_WRBLKFLASHINT(1U)
+
+#define S_BLKWRBOOTINT    4
+#define V_BLKWRBOOTINT(x) ((x) << S_BLKWRBOOTINT)
+#define F_BLKWRBOOTINT    V_BLKWRBOOTINT(1U)
+
+#define S_FLASHRANGEINT    2
+#define V_FLASHRANGEINT(x) ((x) << S_FLASHRANGEINT)
+#define F_FLASHRANGEINT    V_FLASHRANGEINT(1U)
+
+#define S_SDRAMRANGEINT    1
+#define V_SDRAMRANGEINT(x) ((x) << S_SDRAMRANGEINT)
+#define F_SDRAMRANGEINT    V_SDRAMRANGEINT(1U)
+
+#define S_RSVDSPACEINT    0
+#define V_RSVDSPACEINT(x) ((x) << S_RSVDSPACEINT)
+#define F_RSVDSPACEINT    V_RSVDSPACEINT(1U)
+
+#define A_CIM_HOST_ACC_CTRL 0x2b0
+
+#define S_HOSTBUSY    17
+#define V_HOSTBUSY(x) ((x) << S_HOSTBUSY)
+#define F_HOSTBUSY    V_HOSTBUSY(1U)
+
+#define A_CIM_HOST_ACC_DATA 0x2b4
+
+#define A_TP_IN_CONFIG 0x300
+
+#define S_NICMODE    14
+#define V_NICMODE(x) ((x) << S_NICMODE)
+#define F_NICMODE    V_NICMODE(1U)
+
+#define F_NICMODE    V_NICMODE(1U)
+
+#define S_IPV6ENABLE    15
+#define V_IPV6ENABLE(x) ((x) << S_IPV6ENABLE)
+#define F_IPV6ENABLE    V_IPV6ENABLE(1U)
+
+#define A_TP_OUT_CONFIG 0x304
+
+#define S_VLANEXTRACTIONENABLE    12
+
+#define A_TP_GLOBAL_CONFIG 0x308
+
+#define S_TXPACINGENABLE    24
+#define V_TXPACINGENABLE(x) ((x) << S_TXPACINGENABLE)
+#define F_TXPACINGENABLE    V_TXPACINGENABLE(1U)
+
+#define S_PATHMTU    15
+#define V_PATHMTU(x) ((x) << S_PATHMTU)
+#define F_PATHMTU    V_PATHMTU(1U)
+
+#define S_IPCHECKSUMOFFLOAD    13
+#define V_IPCHECKSUMOFFLOAD(x) ((x) << S_IPCHECKSUMOFFLOAD)
+#define F_IPCHECKSUMOFFLOAD    V_IPCHECKSUMOFFLOAD(1U)
+
+#define S_UDPCHECKSUMOFFLOAD    12
+#define V_UDPCHECKSUMOFFLOAD(x) ((x) << S_UDPCHECKSUMOFFLOAD)
+#define F_UDPCHECKSUMOFFLOAD    V_UDPCHECKSUMOFFLOAD(1U)
+
+#define S_TCPCHECKSUMOFFLOAD    11
+#define V_TCPCHECKSUMOFFLOAD(x) ((x) << S_TCPCHECKSUMOFFLOAD)
+#define F_TCPCHECKSUMOFFLOAD    V_TCPCHECKSUMOFFLOAD(1U)
+
+#define S_IPTTL    0
+#define M_IPTTL    0xff
+#define V_IPTTL(x) ((x) << S_IPTTL)
+
+#define A_TP_CMM_MM_BASE 0x314
+
+#define A_TP_CMM_TIMER_BASE 0x318
+
+#define S_CMTIMERMAXNUM    28
+#define M_CMTIMERMAXNUM    0x3
+#define V_CMTIMERMAXNUM(x) ((x) << S_CMTIMERMAXNUM)
+
+#define A_TP_PMM_SIZE 0x31c
+
+#define A_TP_PMM_TX_BASE 0x320
+
+#define A_TP_PMM_RX_BASE 0x328
+
+#define A_TP_PMM_RX_PAGE_SIZE 0x32c
+
+#define A_TP_PMM_RX_MAX_PAGE 0x330
+
+#define A_TP_PMM_TX_PAGE_SIZE 0x334
+
+#define A_TP_PMM_TX_MAX_PAGE 0x338
+
+#define A_TP_TCP_OPTIONS 0x340
+
+#define S_MTUDEFAULT    16
+#define M_MTUDEFAULT    0xffff
+#define V_MTUDEFAULT(x) ((x) << S_MTUDEFAULT)
+
+#define S_MTUENABLE    10
+#define V_MTUENABLE(x) ((x) << S_MTUENABLE)
+#define F_MTUENABLE    V_MTUENABLE(1U)
+
+#define S_SACKRX    8
+#define V_SACKRX(x) ((x) << S_SACKRX)
+#define F_SACKRX    V_SACKRX(1U)
+
+#define S_SACKMODE    4
+
+#define M_SACKMODE    0x3
+
+#define V_SACKMODE(x) ((x) << S_SACKMODE)
+
+#define S_WINDOWSCALEMODE    2
+#define M_WINDOWSCALEMODE    0x3
+#define V_WINDOWSCALEMODE(x) ((x) << S_WINDOWSCALEMODE)
+
+#define S_TIMESTAMPSMODE    0
+
+#define M_TIMESTAMPSMODE    0x3
+
+#define V_TIMESTAMPSMODE(x) ((x) << S_TIMESTAMPSMODE)
+
+#define A_TP_DACK_CONFIG 0x344
+
+#define S_AUTOSTATE3    30
+#define M_AUTOSTATE3    0x3
+#define V_AUTOSTATE3(x) ((x) << S_AUTOSTATE3)
+
+#define S_AUTOSTATE2    28
+#define M_AUTOSTATE2    0x3
+#define V_AUTOSTATE2(x) ((x) << S_AUTOSTATE2)
+
+#define S_AUTOSTATE1    26
+#define M_AUTOSTATE1    0x3
+#define V_AUTOSTATE1(x) ((x) << S_AUTOSTATE1)
+
+#define S_BYTETHRESHOLD    5
+#define M_BYTETHRESHOLD    0xfffff
+#define V_BYTETHRESHOLD(x) ((x) << S_BYTETHRESHOLD)
+
+#define S_MSSTHRESHOLD    3
+#define M_MSSTHRESHOLD    0x3
+#define V_MSSTHRESHOLD(x) ((x) << S_MSSTHRESHOLD)
+
+#define S_AUTOCAREFUL    2
+#define V_AUTOCAREFUL(x) ((x) << S_AUTOCAREFUL)
+#define F_AUTOCAREFUL    V_AUTOCAREFUL(1U)
+
+#define S_AUTOENABLE    1
+#define V_AUTOENABLE(x) ((x) << S_AUTOENABLE)
+#define F_AUTOENABLE    V_AUTOENABLE(1U)
+
+#define S_DACK_MODE    0
+#define V_DACK_MODE(x) ((x) << S_DACK_MODE)
+#define F_DACK_MODE    V_DACK_MODE(1U)
+
+#define A_TP_PC_CONFIG 0x348
+
+#define S_TXTOSQUEUEMAPMODE    26
+#define V_TXTOSQUEUEMAPMODE(x) ((x) << S_TXTOSQUEUEMAPMODE)
+#define F_TXTOSQUEUEMAPMODE    V_TXTOSQUEUEMAPMODE(1U)
+
+#define S_ENABLEEPCMDAFULL    23
+#define V_ENABLEEPCMDAFULL(x) ((x) << S_ENABLEEPCMDAFULL)
+#define F_ENABLEEPCMDAFULL    V_ENABLEEPCMDAFULL(1U)
+
+#define S_MODULATEUNIONMODE    22
+#define V_MODULATEUNIONMODE(x) ((x) << S_MODULATEUNIONMODE)
+#define F_MODULATEUNIONMODE    V_MODULATEUNIONMODE(1U)
+
+#define S_TXDEFERENABLE    20
+#define V_TXDEFERENABLE(x) ((x) << S_TXDEFERENABLE)
+#define F_TXDEFERENABLE    V_TXDEFERENABLE(1U)
+
+#define S_RXCONGESTIONMODE    19
+#define V_RXCONGESTIONMODE(x) ((x) << S_RXCONGESTIONMODE)
+#define F_RXCONGESTIONMODE    V_RXCONGESTIONMODE(1U)
+
+#define S_HEARBEATDACK    16
+#define V_HEARBEATDACK(x) ((x) << S_HEARBEATDACK)
+#define F_HEARBEATDACK    V_HEARBEATDACK(1U)
+
+#define S_TXCONGESTIONMODE    15
+#define V_TXCONGESTIONMODE(x) ((x) << S_TXCONGESTIONMODE)
+#define F_TXCONGESTIONMODE    V_TXCONGESTIONMODE(1U)
+
+#define S_ENABLEOCSPIFULL    30
+#define V_ENABLEOCSPIFULL(x) ((x) << S_ENABLEOCSPIFULL)
+#define F_ENABLEOCSPIFULL    V_ENABLEOCSPIFULL(1U)
+
+#define S_LOCKTID    28
+#define V_LOCKTID(x) ((x) << S_LOCKTID)
+#define F_LOCKTID    V_LOCKTID(1U)
+
+#define A_TP_PC_CONFIG2 0x34c
+
+#define S_CHDRAFULL    4
+#define V_CHDRAFULL(x) ((x) << S_CHDRAFULL)
+#define F_CHDRAFULL    V_CHDRAFULL(1U)
+
+#define A_TP_TCP_BACKOFF_REG0 0x350
+
+#define A_TP_TCP_BACKOFF_REG1 0x354
+
+#define A_TP_TCP_BACKOFF_REG2 0x358
+
+#define A_TP_TCP_BACKOFF_REG3 0x35c
+
+#define A_TP_PARA_REG2 0x368
+
+#define S_MAXRXDATA    16
+#define M_MAXRXDATA    0xffff
+#define V_MAXRXDATA(x) ((x) << S_MAXRXDATA)
+
+#define S_RXCOALESCESIZE    0
+#define M_RXCOALESCESIZE    0xffff
+#define V_RXCOALESCESIZE(x) ((x) << S_RXCOALESCESIZE)
+
+#define A_TP_PARA_REG3 0x36c
+
+#define S_TXDATAACKIDX    16
+#define M_TXDATAACKIDX    0xf
+
+#define V_TXDATAACKIDX(x) ((x) << S_TXDATAACKIDX)
+
+#define S_TXPACEAUTOSTRICT    10
+#define V_TXPACEAUTOSTRICT(x) ((x) << S_TXPACEAUTOSTRICT)
+#define F_TXPACEAUTOSTRICT    V_TXPACEAUTOSTRICT(1U)
+
+#define S_TXPACEFIXED    9
+#define V_TXPACEFIXED(x) ((x) << S_TXPACEFIXED)
+#define F_TXPACEFIXED    V_TXPACEFIXED(1U)
+
+#define S_TXPACEAUTO    8
+#define V_TXPACEAUTO(x) ((x) << S_TXPACEAUTO)
+#define F_TXPACEAUTO    V_TXPACEAUTO(1U)
+
+#define S_RXCOALESCEENABLE    1
+#define V_RXCOALESCEENABLE(x) ((x) << S_RXCOALESCEENABLE)
+#define F_RXCOALESCEENABLE    V_RXCOALESCEENABLE(1U)
+
+#define S_RXCOALESCEPSHEN    0
+#define V_RXCOALESCEPSHEN(x) ((x) << S_RXCOALESCEPSHEN)
+#define F_RXCOALESCEPSHEN    V_RXCOALESCEPSHEN(1U)
+
+#define A_TP_PARA_REG4 0x370
+
+#define A_TP_PARA_REG6 0x378
+
+#define S_T3A_ENABLEESND    13
+#define V_T3A_ENABLEESND(x) ((x) << S_T3A_ENABLEESND)
+#define F_T3A_ENABLEESND    V_T3A_ENABLEESND(1U)
+
+#define S_ENABLEESND    11
+#define V_ENABLEESND(x) ((x) << S_ENABLEESND)
+#define F_ENABLEESND    V_ENABLEESND(1U)
+
+#define A_TP_PARA_REG7 0x37c
+
+#define S_PMMAXXFERLEN1    16
+#define M_PMMAXXFERLEN1    0xffff
+#define V_PMMAXXFERLEN1(x) ((x) << S_PMMAXXFERLEN1)
+
+#define S_PMMAXXFERLEN0    0
+#define M_PMMAXXFERLEN0    0xffff
+#define V_PMMAXXFERLEN0(x) ((x) << S_PMMAXXFERLEN0)
+
+#define A_TP_TIMER_RESOLUTION 0x390
+
+#define S_TIMERRESOLUTION    16
+#define M_TIMERRESOLUTION    0xff
+#define V_TIMERRESOLUTION(x) ((x) << S_TIMERRESOLUTION)
+
+#define S_TIMESTAMPRESOLUTION    8
+#define M_TIMESTAMPRESOLUTION    0xff
+#define V_TIMESTAMPRESOLUTION(x) ((x) << S_TIMESTAMPRESOLUTION)
+
+#define S_DELAYEDACKRESOLUTION    0
+#define M_DELAYEDACKRESOLUTION    0xff
+#define V_DELAYEDACKRESOLUTION(x) ((x) << S_DELAYEDACKRESOLUTION)
+
+#define A_TP_MSL 0x394
+
+#define A_TP_RXT_MIN 0x398
+
+#define A_TP_RXT_MAX 0x39c
+
+#define A_TP_PERS_MIN 0x3a0
+
+#define A_TP_PERS_MAX 0x3a4
+
+#define A_TP_KEEP_IDLE 0x3a8
+
+#define A_TP_KEEP_INTVL 0x3ac
+
+#define A_TP_INIT_SRTT 0x3b0
+
+#define A_TP_DACK_TIMER 0x3b4
+
+#define A_TP_FINWAIT2_TIMER 0x3b8
+
+#define A_TP_SHIFT_CNT 0x3c0
+
+#define S_SYNSHIFTMAX    24
+
+#define M_SYNSHIFTMAX    0xff
+
+#define V_SYNSHIFTMAX(x) ((x) << S_SYNSHIFTMAX)
+
+#define S_RXTSHIFTMAXR1    20
+
+#define M_RXTSHIFTMAXR1    0xf
+
+#define V_RXTSHIFTMAXR1(x) ((x) << S_RXTSHIFTMAXR1)
+
+#define S_RXTSHIFTMAXR2    16
+
+#define M_RXTSHIFTMAXR2    0xf
+
+#define V_RXTSHIFTMAXR2(x) ((x) << S_RXTSHIFTMAXR2)
+
+#define S_PERSHIFTBACKOFFMAX    12
+#define M_PERSHIFTBACKOFFMAX    0xf
+#define V_PERSHIFTBACKOFFMAX(x) ((x) << S_PERSHIFTBACKOFFMAX)
+
+#define S_PERSHIFTMAX    8
+#define M_PERSHIFTMAX    0xf
+#define V_PERSHIFTMAX(x) ((x) << S_PERSHIFTMAX)
+
+#define S_KEEPALIVEMAX    0
+
+#define M_KEEPALIVEMAX    0xff
+
+#define V_KEEPALIVEMAX(x) ((x) << S_KEEPALIVEMAX)
+
+#define A_TP_MTU_PORT_TABLE 0x3d0
+
+#define A_TP_CCTRL_TABLE 0x3dc
+
+#define A_TP_MTU_TABLE 0x3e4
+
+#define A_TP_RSS_MAP_TABLE 0x3e8
+
+#define A_TP_RSS_LKP_TABLE 0x3ec
+
+#define A_TP_RSS_CONFIG 0x3f0
+
+#define S_TNL4TUPEN    29
+#define V_TNL4TUPEN(x) ((x) << S_TNL4TUPEN)
+#define F_TNL4TUPEN    V_TNL4TUPEN(1U)
+
+#define S_TNL2TUPEN    28
+#define V_TNL2TUPEN(x) ((x) << S_TNL2TUPEN)
+#define F_TNL2TUPEN    V_TNL2TUPEN(1U)
+
+#define S_TNLPRTEN    26
+#define V_TNLPRTEN(x) ((x) << S_TNLPRTEN)
+#define F_TNLPRTEN    V_TNLPRTEN(1U)
+
+#define S_TNLMAPEN    25
+#define V_TNLMAPEN(x) ((x) << S_TNLMAPEN)
+#define F_TNLMAPEN    V_TNLMAPEN(1U)
+
+#define S_TNLLKPEN    24
+#define V_TNLLKPEN(x) ((x) << S_TNLLKPEN)
+#define F_TNLLKPEN    V_TNLLKPEN(1U)
+
+#define S_RRCPLCPUSIZE    4
+#define M_RRCPLCPUSIZE    0x7
+#define V_RRCPLCPUSIZE(x) ((x) << S_RRCPLCPUSIZE)
+
+#define S_RQFEEDBACKENABLE    3
+#define V_RQFEEDBACKENABLE(x) ((x) << S_RQFEEDBACKENABLE)
+#define F_RQFEEDBACKENABLE    V_RQFEEDBACKENABLE(1U)
+
+#define S_DISABLE    0
+
+#define A_TP_TM_PIO_ADDR 0x418
+
+#define A_TP_TM_PIO_DATA 0x41c
+
+#define A_TP_TX_MOD_QUE_TABLE 0x420
+
+#define A_TP_TX_RESOURCE_LIMIT 0x424
+
+#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x428
+
+#define S_TX_MOD_QUEUE_REQ_MAP    0
+#define M_TX_MOD_QUEUE_REQ_MAP    0xff
+#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP)
+
+#define A_TP_TX_MOD_QUEUE_WEIGHT1 0x42c
+
+#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x430
+
+#define A_TP_MOD_CHANNEL_WEIGHT 0x434
+
+#define A_TP_PIO_ADDR 0x440
+
+#define A_TP_PIO_DATA 0x444
+
+#define A_TP_RESET 0x44c
+
+#define S_FLSTINITENABLE    1
+#define V_FLSTINITENABLE(x) ((x) << S_FLSTINITENABLE)
+#define F_FLSTINITENABLE    V_FLSTINITENABLE(1U)
+
+#define S_TPRESET    0
+#define V_TPRESET(x) ((x) << S_TPRESET)
+#define F_TPRESET    V_TPRESET(1U)
+
+#define A_TP_CMM_MM_RX_FLST_BASE 0x460
+
+#define A_TP_CMM_MM_TX_FLST_BASE 0x464
+
+#define A_TP_CMM_MM_PS_FLST_BASE 0x468
+
+#define A_TP_MIB_INDEX 0x450
+
+#define A_TP_MIB_RDATA 0x454
+
+#define A_TP_CMM_MM_MAX_PSTRUCT 0x46c
+
+#define A_TP_INT_ENABLE 0x470
+
+#define A_TP_INT_CAUSE 0x474
+
+#define A_TP_TX_MOD_Q1_Q0_RATE_LIMIT 0x8
+
+#define A_TP_TX_DROP_CFG_CH0 0x12b
+
+#define A_TP_TX_DROP_MODE 0x12f
+
+#define A_TP_EGRESS_CONFIG 0x145
+
+#define S_REWRITEFORCETOSIZE    0
+#define V_REWRITEFORCETOSIZE(x) ((x) << S_REWRITEFORCETOSIZE)
+#define F_REWRITEFORCETOSIZE    V_REWRITEFORCETOSIZE(1U)
+
+#define A_TP_TX_TRC_KEY0 0x20
+
+#define A_TP_RX_TRC_KEY0 0x120
+
+#define A_ULPRX_CTL 0x500
+
+#define S_ROUND_ROBIN    4
+#define V_ROUND_ROBIN(x) ((x) << S_ROUND_ROBIN)
+#define F_ROUND_ROBIN    V_ROUND_ROBIN(1U)
+
+#define A_ULPRX_INT_ENABLE 0x504
+
+#define S_PARERR    0
+#define V_PARERR(x) ((x) << S_PARERR)
+#define F_PARERR    V_PARERR(1U)
+
+#define A_ULPRX_INT_CAUSE 0x508
+
+#define A_ULPRX_ISCSI_LLIMIT 0x50c
+
+#define A_ULPRX_ISCSI_ULIMIT 0x510
+
+#define A_ULPRX_ISCSI_TAGMASK 0x514
+
+#define A_ULPRX_TDDP_LLIMIT 0x51c
+
+#define A_ULPRX_TDDP_ULIMIT 0x520
+
+#define A_ULPRX_STAG_LLIMIT 0x52c
+
+#define A_ULPRX_STAG_ULIMIT 0x530
+
+#define A_ULPRX_RQ_LLIMIT 0x534
+#define A_ULPRX_RQ_LLIMIT 0x534
+
+#define A_ULPRX_RQ_ULIMIT 0x538
+#define A_ULPRX_RQ_ULIMIT 0x538
+
+#define A_ULPRX_PBL_LLIMIT 0x53c
+
+#define A_ULPRX_PBL_ULIMIT 0x540
+#define A_ULPRX_PBL_ULIMIT 0x540
+
+#define A_ULPRX_TDDP_TAGMASK 0x524
+
+#define A_ULPRX_RQ_LLIMIT 0x534
+#define A_ULPRX_RQ_LLIMIT 0x534
+
+#define A_ULPRX_RQ_ULIMIT 0x538
+#define A_ULPRX_RQ_ULIMIT 0x538
+
+#define A_ULPRX_PBL_ULIMIT 0x540
+#define A_ULPRX_PBL_ULIMIT 0x540
+
+#define A_ULPTX_CONFIG 0x580
+
+#define S_CFG_RR_ARB    0
+#define V_CFG_RR_ARB(x) ((x) << S_CFG_RR_ARB)
+#define F_CFG_RR_ARB    V_CFG_RR_ARB(1U)
+
+#define A_ULPTX_INT_ENABLE 0x584
+
+#define S_PBL_BOUND_ERR_CH1    1
+#define V_PBL_BOUND_ERR_CH1(x) ((x) << S_PBL_BOUND_ERR_CH1)
+#define F_PBL_BOUND_ERR_CH1    V_PBL_BOUND_ERR_CH1(1U)
+
+#define S_PBL_BOUND_ERR_CH0    0
+#define V_PBL_BOUND_ERR_CH0(x) ((x) << S_PBL_BOUND_ERR_CH0)
+#define F_PBL_BOUND_ERR_CH0    V_PBL_BOUND_ERR_CH0(1U)
+
+#define A_ULPTX_INT_CAUSE 0x588
+
+#define A_ULPTX_TPT_LLIMIT 0x58c
+
+#define A_ULPTX_TPT_ULIMIT 0x590
+
+#define A_ULPTX_PBL_LLIMIT 0x594
+
+#define A_ULPTX_PBL_ULIMIT 0x598
+
+#define A_ULPTX_DMA_WEIGHT 0x5ac
+
+#define S_D1_WEIGHT    16
+#define M_D1_WEIGHT    0xffff
+#define V_D1_WEIGHT(x) ((x) << S_D1_WEIGHT)
+
+#define S_D0_WEIGHT    0
+#define M_D0_WEIGHT    0xffff
+#define V_D0_WEIGHT(x) ((x) << S_D0_WEIGHT)
+
+#define A_PM1_RX_CFG 0x5c0
+
+#define A_PM1_RX_INT_ENABLE 0x5d8
+
+#define S_ZERO_E_CMD_ERROR    18
+#define V_ZERO_E_CMD_ERROR(x) ((x) << S_ZERO_E_CMD_ERROR)
+#define F_ZERO_E_CMD_ERROR    V_ZERO_E_CMD_ERROR(1U)
+
+#define S_IESPI0_FIFO2X_RX_FRAMING_ERROR    17
+#define V_IESPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_FIFO2X_RX_FRAMING_ERROR)
+#define F_IESPI0_FIFO2X_RX_FRAMING_ERROR    V_IESPI0_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_FIFO2X_RX_FRAMING_ERROR    16
+#define V_IESPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_FIFO2X_RX_FRAMING_ERROR)
+#define F_IESPI1_FIFO2X_RX_FRAMING_ERROR    V_IESPI1_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI0_RX_FRAMING_ERROR    15
+#define V_IESPI0_RX_FRAMING_ERROR(x) ((x) << S_IESPI0_RX_FRAMING_ERROR)
+#define F_IESPI0_RX_FRAMING_ERROR    V_IESPI0_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_RX_FRAMING_ERROR    14
+#define V_IESPI1_RX_FRAMING_ERROR(x) ((x) << S_IESPI1_RX_FRAMING_ERROR)
+#define F_IESPI1_RX_FRAMING_ERROR    V_IESPI1_RX_FRAMING_ERROR(1U)
+
+#define S_IESPI0_TX_FRAMING_ERROR    13
+#define V_IESPI0_TX_FRAMING_ERROR(x) ((x) << S_IESPI0_TX_FRAMING_ERROR)
+#define F_IESPI0_TX_FRAMING_ERROR    V_IESPI0_TX_FRAMING_ERROR(1U)
+
+#define S_IESPI1_TX_FRAMING_ERROR    12
+#define V_IESPI1_TX_FRAMING_ERROR(x) ((x) << S_IESPI1_TX_FRAMING_ERROR)
+#define F_IESPI1_TX_FRAMING_ERROR    V_IESPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_RX_FRAMING_ERROR    11
+#define V_OCSPI0_RX_FRAMING_ERROR(x) ((x) << S_OCSPI0_RX_FRAMING_ERROR)
+#define F_OCSPI0_RX_FRAMING_ERROR    V_OCSPI0_RX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_RX_FRAMING_ERROR    10
+#define V_OCSPI1_RX_FRAMING_ERROR(x) ((x) << S_OCSPI1_RX_FRAMING_ERROR)
+#define F_OCSPI1_RX_FRAMING_ERROR    V_OCSPI1_RX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_TX_FRAMING_ERROR    9
+#define V_OCSPI0_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_TX_FRAMING_ERROR)
+#define F_OCSPI0_TX_FRAMING_ERROR    V_OCSPI0_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_TX_FRAMING_ERROR    8
+#define V_OCSPI1_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_TX_FRAMING_ERROR)
+#define F_OCSPI1_TX_FRAMING_ERROR    V_OCSPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR    7
+#define V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI0_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR    V_OCSPI0_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR    6
+#define V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR    V_OCSPI1_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_IESPI_PAR_ERROR    3
+#define M_IESPI_PAR_ERROR    0x7
+
+#define V_IESPI_PAR_ERROR(x) ((x) << S_IESPI_PAR_ERROR)
+
+#define S_OCSPI_PAR_ERROR    0
+#define M_OCSPI_PAR_ERROR    0x7
+
+#define V_OCSPI_PAR_ERROR(x) ((x) << S_OCSPI_PAR_ERROR)
+
+#define A_PM1_RX_INT_CAUSE 0x5dc
+
+#define A_PM1_TX_CFG 0x5e0
+
+#define A_PM1_TX_INT_ENABLE 0x5f8
+
+#define S_ZERO_C_CMD_ERROR    18
+#define V_ZERO_C_CMD_ERROR(x) ((x) << S_ZERO_C_CMD_ERROR)
+#define F_ZERO_C_CMD_ERROR    V_ZERO_C_CMD_ERROR(1U)
+
+#define S_ICSPI0_FIFO2X_RX_FRAMING_ERROR    17
+#define V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_FIFO2X_RX_FRAMING_ERROR)
+#define F_ICSPI0_FIFO2X_RX_FRAMING_ERROR    V_ICSPI0_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_FIFO2X_RX_FRAMING_ERROR    16
+#define V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_FIFO2X_RX_FRAMING_ERROR)
+#define F_ICSPI1_FIFO2X_RX_FRAMING_ERROR    V_ICSPI1_FIFO2X_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI0_RX_FRAMING_ERROR    15
+#define V_ICSPI0_RX_FRAMING_ERROR(x) ((x) << S_ICSPI0_RX_FRAMING_ERROR)
+#define F_ICSPI0_RX_FRAMING_ERROR    V_ICSPI0_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_RX_FRAMING_ERROR    14
+#define V_ICSPI1_RX_FRAMING_ERROR(x) ((x) << S_ICSPI1_RX_FRAMING_ERROR)
+#define F_ICSPI1_RX_FRAMING_ERROR    V_ICSPI1_RX_FRAMING_ERROR(1U)
+
+#define S_ICSPI0_TX_FRAMING_ERROR    13
+#define V_ICSPI0_TX_FRAMING_ERROR(x) ((x) << S_ICSPI0_TX_FRAMING_ERROR)
+#define F_ICSPI0_TX_FRAMING_ERROR    V_ICSPI0_TX_FRAMING_ERROR(1U)
+
+#define S_ICSPI1_TX_FRAMING_ERROR    12
+#define V_ICSPI1_TX_FRAMING_ERROR(x) ((x) << S_ICSPI1_TX_FRAMING_ERROR)
+#define F_ICSPI1_TX_FRAMING_ERROR    V_ICSPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_RX_FRAMING_ERROR    11
+#define V_OESPI0_RX_FRAMING_ERROR(x) ((x) << S_OESPI0_RX_FRAMING_ERROR)
+#define F_OESPI0_RX_FRAMING_ERROR    V_OESPI0_RX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_RX_FRAMING_ERROR    10
+#define V_OESPI1_RX_FRAMING_ERROR(x) ((x) << S_OESPI1_RX_FRAMING_ERROR)
+#define F_OESPI1_RX_FRAMING_ERROR    V_OESPI1_RX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_TX_FRAMING_ERROR    9
+#define V_OESPI0_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_TX_FRAMING_ERROR)
+#define F_OESPI0_TX_FRAMING_ERROR    V_OESPI0_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_TX_FRAMING_ERROR    8
+#define V_OESPI1_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_TX_FRAMING_ERROR)
+#define F_OESPI1_TX_FRAMING_ERROR    V_OESPI1_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI0_OFIFO2X_TX_FRAMING_ERROR    7
+#define V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI0_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OESPI0_OFIFO2X_TX_FRAMING_ERROR    V_OESPI0_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_OESPI1_OFIFO2X_TX_FRAMING_ERROR    6
+#define V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(x) ((x) << S_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
+#define F_OESPI1_OFIFO2X_TX_FRAMING_ERROR    V_OESPI1_OFIFO2X_TX_FRAMING_ERROR(1U)
+
+#define S_ICSPI_PAR_ERROR    3
+#define M_ICSPI_PAR_ERROR    0x7
+
+#define V_ICSPI_PAR_ERROR(x) ((x) << S_ICSPI_PAR_ERROR)
+
+#define S_OESPI_PAR_ERROR    0
+#define M_OESPI_PAR_ERROR    0x7
+
+#define V_OESPI_PAR_ERROR(x) ((x) << S_OESPI_PAR_ERROR)
+
+#define A_PM1_TX_INT_CAUSE 0x5fc
+
+#define A_MPS_CFG 0x600
+
+#define S_TPRXPORTEN    4
+#define V_TPRXPORTEN(x) ((x) << S_TPRXPORTEN)
+#define F_TPRXPORTEN    V_TPRXPORTEN(1U)
+
+#define S_TPTXPORT1EN    3
+#define V_TPTXPORT1EN(x) ((x) << S_TPTXPORT1EN)
+#define F_TPTXPORT1EN    V_TPTXPORT1EN(1U)
+
+#define S_TPTXPORT0EN    2
+#define V_TPTXPORT0EN(x) ((x) << S_TPTXPORT0EN)
+#define F_TPTXPORT0EN    V_TPTXPORT0EN(1U)
+
+#define S_PORT1ACTIVE    1
+#define V_PORT1ACTIVE(x) ((x) << S_PORT1ACTIVE)
+#define F_PORT1ACTIVE    V_PORT1ACTIVE(1U)
+
+#define S_PORT0ACTIVE    0
+#define V_PORT0ACTIVE(x) ((x) << S_PORT0ACTIVE)
+#define F_PORT0ACTIVE    V_PORT0ACTIVE(1U)
+
+#define S_ENFORCEPKT    11
+#define V_ENFORCEPKT(x) ((x) << S_ENFORCEPKT)
+#define F_ENFORCEPKT    V_ENFORCEPKT(1U)
+
+#define A_MPS_INT_ENABLE 0x61c
+
+#define S_MCAPARERRENB    6
+#define M_MCAPARERRENB    0x7
+
+#define V_MCAPARERRENB(x) ((x) << S_MCAPARERRENB)
+
+#define S_RXTPPARERRENB    4
+#define M_RXTPPARERRENB    0x3
+
+#define V_RXTPPARERRENB(x) ((x) << S_RXTPPARERRENB)
+
+#define S_TX1TPPARERRENB    2
+#define M_TX1TPPARERRENB    0x3
+
+#define V_TX1TPPARERRENB(x) ((x) << S_TX1TPPARERRENB)
+
+#define S_TX0TPPARERRENB    0
+#define M_TX0TPPARERRENB    0x3
+
+#define V_TX0TPPARERRENB(x) ((x) << S_TX0TPPARERRENB)
+
+#define A_MPS_INT_CAUSE 0x620
+
+#define S_MCAPARERR    6
+#define M_MCAPARERR    0x7
+
+#define V_MCAPARERR(x) ((x) << S_MCAPARERR)
+
+#define S_RXTPPARERR    4
+#define M_RXTPPARERR    0x3
+
+#define V_RXTPPARERR(x) ((x) << S_RXTPPARERR)
+
+#define S_TX1TPPARERR    2
+#define M_TX1TPPARERR    0x3
+
+#define V_TX1TPPARERR(x) ((x) << S_TX1TPPARERR)
+
+#define S_TX0TPPARERR    0
+#define M_TX0TPPARERR    0x3
+
+#define V_TX0TPPARERR(x) ((x) << S_TX0TPPARERR)
+
+#define A_CPL_SWITCH_CNTRL 0x640
+
+#define A_CPL_INTR_ENABLE 0x650
+
+#define S_CIM_OVFL_ERROR    4
+#define V_CIM_OVFL_ERROR(x) ((x) << S_CIM_OVFL_ERROR)
+#define F_CIM_OVFL_ERROR    V_CIM_OVFL_ERROR(1U)
+
+#define S_TP_FRAMING_ERROR    3
+#define V_TP_FRAMING_ERROR(x) ((x) << S_TP_FRAMING_ERROR)
+#define F_TP_FRAMING_ERROR    V_TP_FRAMING_ERROR(1U)
+
+#define S_SGE_FRAMING_ERROR    2
+#define V_SGE_FRAMING_ERROR(x) ((x) << S_SGE_FRAMING_ERROR)
+#define F_SGE_FRAMING_ERROR    V_SGE_FRAMING_ERROR(1U)
+
+#define S_CIM_FRAMING_ERROR    1
+#define V_CIM_FRAMING_ERROR(x) ((x) << S_CIM_FRAMING_ERROR)
+#define F_CIM_FRAMING_ERROR    V_CIM_FRAMING_ERROR(1U)
+
+#define S_ZERO_SWITCH_ERROR    0
+#define V_ZERO_SWITCH_ERROR(x) ((x) << S_ZERO_SWITCH_ERROR)
+#define F_ZERO_SWITCH_ERROR    V_ZERO_SWITCH_ERROR(1U)
+
+#define A_CPL_INTR_CAUSE 0x654
+
+#define A_CPL_MAP_TBL_DATA 0x65c
+
+#define A_SMB_GLOBAL_TIME_CFG 0x660
+
+#define A_I2C_CFG 0x6a0
+
+#define S_I2C_CLKDIV    0
+#define M_I2C_CLKDIV    0xfff
+#define V_I2C_CLKDIV(x) ((x) << S_I2C_CLKDIV)
+
+#define A_MI1_CFG 0x6b0
+
+#define S_CLKDIV    5
+#define M_CLKDIV    0xff
+#define V_CLKDIV(x) ((x) << S_CLKDIV)
+
+#define S_ST    3
+
+#define M_ST    0x3
+
+#define V_ST(x) ((x) << S_ST)
+
+#define G_ST(x) (((x) >> S_ST) & M_ST)
+
+#define S_PREEN    2
+#define V_PREEN(x) ((x) << S_PREEN)
+#define F_PREEN    V_PREEN(1U)
+
+#define S_MDIINV    1
+#define V_MDIINV(x) ((x) << S_MDIINV)
+#define F_MDIINV    V_MDIINV(1U)
+
+#define S_MDIEN    0
+#define V_MDIEN(x) ((x) << S_MDIEN)
+#define F_MDIEN    V_MDIEN(1U)
+
+#define A_MI1_ADDR 0x6b4
+
+#define S_PHYADDR    5
+#define M_PHYADDR    0x1f
+#define V_PHYADDR(x) ((x) << S_PHYADDR)
+
+#define S_REGADDR    0
+#define M_REGADDR    0x1f
+#define V_REGADDR(x) ((x) << S_REGADDR)
+
+#define A_MI1_DATA 0x6b8
+
+#define A_MI1_OP 0x6bc
+
+#define S_MDI_OP    0
+#define M_MDI_OP    0x3
+#define V_MDI_OP(x) ((x) << S_MDI_OP)
+
+#define A_SF_DATA 0x6d8
+
+#define A_SF_OP 0x6dc
+
+#define S_BYTECNT    1
+#define M_BYTECNT    0x3
+#define V_BYTECNT(x) ((x) << S_BYTECNT)
+
+#define A_PL_INT_ENABLE0 0x6e0
+
+#define S_T3DBG    23
+#define V_T3DBG(x) ((x) << S_T3DBG)
+#define F_T3DBG    V_T3DBG(1U)
+
+#define S_XGMAC0_1    20
+#define V_XGMAC0_1(x) ((x) << S_XGMAC0_1)
+#define F_XGMAC0_1    V_XGMAC0_1(1U)
+
+#define S_XGMAC0_0    19
+#define V_XGMAC0_0(x) ((x) << S_XGMAC0_0)
+#define F_XGMAC0_0    V_XGMAC0_0(1U)
+
+#define S_MC5A    18
+#define V_MC5A(x) ((x) << S_MC5A)
+#define F_MC5A    V_MC5A(1U)
+
+#define S_CPL_SWITCH    12
+#define V_CPL_SWITCH(x) ((x) << S_CPL_SWITCH)
+#define F_CPL_SWITCH    V_CPL_SWITCH(1U)
+
+#define S_MPS0    11
+#define V_MPS0(x) ((x) << S_MPS0)
+#define F_MPS0    V_MPS0(1U)
+
+#define S_PM1_TX    10
+#define V_PM1_TX(x) ((x) << S_PM1_TX)
+#define F_PM1_TX    V_PM1_TX(1U)
+
+#define S_PM1_RX    9
+#define V_PM1_RX(x) ((x) << S_PM1_RX)
+#define F_PM1_RX    V_PM1_RX(1U)
+
+#define S_ULP2_TX    8
+#define V_ULP2_TX(x) ((x) << S_ULP2_TX)
+#define F_ULP2_TX    V_ULP2_TX(1U)
+
+#define S_ULP2_RX    7
+#define V_ULP2_RX(x) ((x) << S_ULP2_RX)
+#define F_ULP2_RX    V_ULP2_RX(1U)
+
+#define S_TP1    6
+#define V_TP1(x) ((x) << S_TP1)
+#define F_TP1    V_TP1(1U)
+
+#define S_CIM    5
+#define V_CIM(x) ((x) << S_CIM)
+#define F_CIM    V_CIM(1U)
+
+#define S_MC7_CM    4
+#define V_MC7_CM(x) ((x) << S_MC7_CM)
+#define F_MC7_CM    V_MC7_CM(1U)
+
+#define S_MC7_PMTX    3
+#define V_MC7_PMTX(x) ((x) << S_MC7_PMTX)
+#define F_MC7_PMTX    V_MC7_PMTX(1U)
+
+#define S_MC7_PMRX    2
+#define V_MC7_PMRX(x) ((x) << S_MC7_PMRX)
+#define F_MC7_PMRX    V_MC7_PMRX(1U)
+
+#define S_PCIM0    1
+#define V_PCIM0(x) ((x) << S_PCIM0)
+#define F_PCIM0    V_PCIM0(1U)
+
+#define S_SGE3    0
+#define V_SGE3(x) ((x) << S_SGE3)
+#define F_SGE3    V_SGE3(1U)
+
+#define A_PL_INT_CAUSE0 0x6e4
+
+#define A_PL_RST 0x6f0
+
+#define S_CRSTWRM    1
+#define V_CRSTWRM(x) ((x) << S_CRSTWRM)
+#define F_CRSTWRM    V_CRSTWRM(1U)
+
+#define A_PL_REV 0x6f4
+
+#define A_PL_CLI 0x6f8
+
+#define A_MC5_DB_CONFIG 0x704
+
+#define S_TMTYPEHI    30
+#define V_TMTYPEHI(x) ((x) << S_TMTYPEHI)
+#define F_TMTYPEHI    V_TMTYPEHI(1U)
+
+#define S_TMPARTSIZE    28
+#define M_TMPARTSIZE    0x3
+#define V_TMPARTSIZE(x) ((x) << S_TMPARTSIZE)
+#define G_TMPARTSIZE(x) (((x) >> S_TMPARTSIZE) & M_TMPARTSIZE)
+
+#define S_TMTYPE    26
+#define M_TMTYPE    0x3
+#define V_TMTYPE(x) ((x) << S_TMTYPE)
+#define G_TMTYPE(x) (((x) >> S_TMTYPE) & M_TMTYPE)
+
+#define S_COMPEN    17
+#define V_COMPEN(x) ((x) << S_COMPEN)
+#define F_COMPEN    V_COMPEN(1U)
+
+#define S_PRTYEN    6
+#define V_PRTYEN(x) ((x) << S_PRTYEN)
+#define F_PRTYEN    V_PRTYEN(1U)
+
+#define S_MBUSEN    5
+#define V_MBUSEN(x) ((x) << S_MBUSEN)
+#define F_MBUSEN    V_MBUSEN(1U)
+
+#define S_DBGIEN    4
+#define V_DBGIEN(x) ((x) << S_DBGIEN)
+#define F_DBGIEN    V_DBGIEN(1U)
+
+#define S_TMRDY    2
+#define V_TMRDY(x) ((x) << S_TMRDY)
+#define F_TMRDY    V_TMRDY(1U)
+
+#define S_TMRST    1
+#define V_TMRST(x) ((x) << S_TMRST)
+#define F_TMRST    V_TMRST(1U)
+
+#define S_TMMODE    0
+#define V_TMMODE(x) ((x) << S_TMMODE)
+#define F_TMMODE    V_TMMODE(1U)
+
+#define F_TMMODE    V_TMMODE(1U)
+
+#define A_MC5_DB_ROUTING_TABLE_INDEX 0x70c
+
+#define A_MC5_DB_FILTER_TABLE 0x710
+
+#define A_MC5_DB_SERVER_INDEX 0x714
+
+#define A_MC5_DB_RSP_LATENCY 0x720
+
+#define S_RDLAT    16
+#define M_RDLAT    0x1f
+#define V_RDLAT(x) ((x) << S_RDLAT)
+
+#define S_LRNLAT    8
+#define M_LRNLAT    0x1f
+#define V_LRNLAT(x) ((x) << S_LRNLAT)
+
+#define S_SRCHLAT    0
+#define M_SRCHLAT    0x1f
+#define V_SRCHLAT(x) ((x) << S_SRCHLAT)
+
+#define A_MC5_DB_PART_ID_INDEX 0x72c
+
+#define A_MC5_DB_INT_ENABLE 0x740
+
+#define S_DELACTEMPTY    18
+#define V_DELACTEMPTY(x) ((x) << S_DELACTEMPTY)
+#define F_DELACTEMPTY    V_DELACTEMPTY(1U)
+
+#define S_DISPQPARERR    17
+#define V_DISPQPARERR(x) ((x) << S_DISPQPARERR)
+#define F_DISPQPARERR    V_DISPQPARERR(1U)
+
+#define S_REQQPARERR    16
+#define V_REQQPARERR(x) ((x) << S_REQQPARERR)
+#define F_REQQPARERR    V_REQQPARERR(1U)
+
+#define S_UNKNOWNCMD    15
+#define V_UNKNOWNCMD(x) ((x) << S_UNKNOWNCMD)
+#define F_UNKNOWNCMD    V_UNKNOWNCMD(1U)
+
+#define S_NFASRCHFAIL    8
+#define V_NFASRCHFAIL(x) ((x) << S_NFASRCHFAIL)
+#define F_NFASRCHFAIL    V_NFASRCHFAIL(1U)
+
+#define S_ACTRGNFULL    7
+#define V_ACTRGNFULL(x) ((x) << S_ACTRGNFULL)
+#define F_ACTRGNFULL    V_ACTRGNFULL(1U)
+
+#define S_PARITYERR    6
+#define V_PARITYERR(x) ((x) << S_PARITYERR)
+#define F_PARITYERR    V_PARITYERR(1U)
+
+#define A_MC5_DB_INT_CAUSE 0x744
+
+#define A_MC5_DB_DBGI_CONFIG 0x774
+
+#define A_MC5_DB_DBGI_REQ_CMD 0x778
+
+#define A_MC5_DB_DBGI_REQ_ADDR0 0x77c
+
+#define A_MC5_DB_DBGI_REQ_ADDR1 0x780
+
+#define A_MC5_DB_DBGI_REQ_ADDR2 0x784
+
+#define A_MC5_DB_DBGI_REQ_DATA0 0x788
+
+#define A_MC5_DB_DBGI_REQ_DATA1 0x78c
+
+#define A_MC5_DB_DBGI_REQ_DATA2 0x790
+
+#define A_MC5_DB_DBGI_RSP_STATUS 0x7b0
+
+#define S_DBGIRSPVALID    0
+#define V_DBGIRSPVALID(x) ((x) << S_DBGIRSPVALID)
+#define F_DBGIRSPVALID    V_DBGIRSPVALID(1U)
+
+#define A_MC5_DB_DBGI_RSP_DATA0 0x7b4
+
+#define A_MC5_DB_DBGI_RSP_DATA1 0x7b8
+
+#define A_MC5_DB_DBGI_RSP_DATA2 0x7bc
+
+#define A_MC5_DB_POPEN_DATA_WR_CMD 0x7cc
+
+#define A_MC5_DB_POPEN_MASK_WR_CMD 0x7d0
+
+#define A_MC5_DB_AOPEN_SRCH_CMD 0x7d4
+
+#define A_MC5_DB_AOPEN_LRN_CMD 0x7d8
+
+#define A_MC5_DB_SYN_SRCH_CMD 0x7dc
+
+#define A_MC5_DB_SYN_LRN_CMD 0x7e0
+
+#define A_MC5_DB_ACK_SRCH_CMD 0x7e4
+
+#define A_MC5_DB_ACK_LRN_CMD 0x7e8
+
+#define A_MC5_DB_ILOOKUP_CMD 0x7ec
+
+#define A_MC5_DB_ELOOKUP_CMD 0x7f0
+
+#define A_MC5_DB_DATA_WRITE_CMD 0x7f4
+
+#define A_MC5_DB_DATA_READ_CMD 0x7f8
+
+#define XGMAC0_0_BASE_ADDR 0x800
+
+#define A_XGM_TX_CTRL 0x800
+
+#define S_TXEN    0
+#define V_TXEN(x) ((x) << S_TXEN)
+#define F_TXEN    V_TXEN(1U)
+
+#define A_XGM_TX_CFG 0x804
+
+#define S_TXPAUSEEN    0
+#define V_TXPAUSEEN(x) ((x) << S_TXPAUSEEN)
+#define F_TXPAUSEEN    V_TXPAUSEEN(1U)
+
+#define A_XGM_RX_CTRL 0x80c
+
+#define S_RXEN    0
+#define V_RXEN(x) ((x) << S_RXEN)
+#define F_RXEN    V_RXEN(1U)
+
+#define A_XGM_RX_CFG 0x810
+
+#define S_DISPAUSEFRAMES    9
+#define V_DISPAUSEFRAMES(x) ((x) << S_DISPAUSEFRAMES)
+#define F_DISPAUSEFRAMES    V_DISPAUSEFRAMES(1U)
+
+#define S_EN1536BFRAMES    8
+#define V_EN1536BFRAMES(x) ((x) << S_EN1536BFRAMES)
+#define F_EN1536BFRAMES    V_EN1536BFRAMES(1U)
+
+#define S_ENJUMBO    7
+#define V_ENJUMBO(x) ((x) << S_ENJUMBO)
+#define F_ENJUMBO    V_ENJUMBO(1U)
+
+#define S_RMFCS    6
+#define V_RMFCS(x) ((x) << S_RMFCS)
+#define F_RMFCS    V_RMFCS(1U)
+
+#define S_ENHASHMCAST    2
+#define V_ENHASHMCAST(x) ((x) << S_ENHASHMCAST)
+#define F_ENHASHMCAST    V_ENHASHMCAST(1U)
+
+#define S_COPYALLFRAMES    0
+#define V_COPYALLFRAMES(x) ((x) << S_COPYALLFRAMES)
+#define F_COPYALLFRAMES    V_COPYALLFRAMES(1U)
+
+#define A_XGM_RX_HASH_LOW 0x814
+
+#define A_XGM_RX_HASH_HIGH 0x818
+
+#define A_XGM_RX_EXACT_MATCH_LOW_1 0x81c
+
+#define A_XGM_RX_EXACT_MATCH_HIGH_1 0x820
+
+#define A_XGM_RX_EXACT_MATCH_LOW_2 0x824
+
+#define A_XGM_RX_EXACT_MATCH_LOW_3 0x82c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_4 0x834
+
+#define A_XGM_RX_EXACT_MATCH_LOW_5 0x83c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_6 0x844
+
+#define A_XGM_RX_EXACT_MATCH_LOW_7 0x84c
+
+#define A_XGM_RX_EXACT_MATCH_LOW_8 0x854
+
+#define A_XGM_STAT_CTRL 0x880
+
+#define S_CLRSTATS    2
+#define V_CLRSTATS(x) ((x) << S_CLRSTATS)
+#define F_CLRSTATS    V_CLRSTATS(1U)
+
+#define A_XGM_RXFIFO_CFG 0x884
+
+#define S_RXFIFOPAUSEHWM    17
+#define M_RXFIFOPAUSEHWM    0xfff
+
+#define V_RXFIFOPAUSEHWM(x) ((x) << S_RXFIFOPAUSEHWM)
+
+#define G_RXFIFOPAUSEHWM(x) (((x) >> S_RXFIFOPAUSEHWM) & M_RXFIFOPAUSEHWM)
+
+#define S_RXFIFOPAUSELWM    5
+#define M_RXFIFOPAUSELWM    0xfff
+
+#define V_RXFIFOPAUSELWM(x) ((x) << S_RXFIFOPAUSELWM)
+
+#define G_RXFIFOPAUSELWM(x) (((x) >> S_RXFIFOPAUSELWM) & M_RXFIFOPAUSELWM)
+
+#define S_RXSTRFRWRD    1
+#define V_RXSTRFRWRD(x) ((x) << S_RXSTRFRWRD)
+#define F_RXSTRFRWRD    V_RXSTRFRWRD(1U)
+
+#define S_DISERRFRAMES    0
+#define V_DISERRFRAMES(x) ((x) << S_DISERRFRAMES)
+#define F_DISERRFRAMES    V_DISERRFRAMES(1U)
+
+#define A_XGM_TXFIFO_CFG 0x888
+
+#define S_TXFIFOTHRESH    4
+#define M_TXFIFOTHRESH    0x1ff
+
+#define V_TXFIFOTHRESH(x) ((x) << S_TXFIFOTHRESH)
+
+#define A_XGM_SERDES_CTRL 0x890
+#define A_XGM_SERDES_CTRL0 0x8e0
+
+#define S_SERDESRESET_    24
+#define V_SERDESRESET_(x) ((x) << S_SERDESRESET_)
+#define F_SERDESRESET_    V_SERDESRESET_(1U)
+
+#define S_RXENABLE    4
+#define V_RXENABLE(x) ((x) << S_RXENABLE)
+#define F_RXENABLE    V_RXENABLE(1U)
+
+#define S_TXENABLE    3
+#define V_TXENABLE(x) ((x) << S_TXENABLE)
+#define F_TXENABLE    V_TXENABLE(1U)
+
+#define A_XGM_PAUSE_TIMER 0x890
+
+#define A_XGM_RGMII_IMP 0x89c
+
+#define S_XGM_IMPSETUPDATE    6
+#define V_XGM_IMPSETUPDATE(x) ((x) << S_XGM_IMPSETUPDATE)
+#define F_XGM_IMPSETUPDATE    V_XGM_IMPSETUPDATE(1U)
+
+#define S_RGMIIIMPPD    3
+#define M_RGMIIIMPPD    0x7
+#define V_RGMIIIMPPD(x) ((x) << S_RGMIIIMPPD)
+
+#define S_RGMIIIMPPU    0
+#define M_RGMIIIMPPU    0x7
+#define V_RGMIIIMPPU(x) ((x) << S_RGMIIIMPPU)
+
+#define S_CALRESET    8
+#define V_CALRESET(x) ((x) << S_CALRESET)
+#define F_CALRESET    V_CALRESET(1U)
+
+#define S_CALUPDATE    7
+#define V_CALUPDATE(x) ((x) << S_CALUPDATE)
+#define F_CALUPDATE    V_CALUPDATE(1U)
+
+#define A_XGM_XAUI_IMP 0x8a0
+
+#define S_CALBUSY    31
+#define V_CALBUSY(x) ((x) << S_CALBUSY)
+#define F_CALBUSY    V_CALBUSY(1U)
+
+#define S_XGM_CALFAULT    29
+#define V_XGM_CALFAULT(x) ((x) << S_XGM_CALFAULT)
+#define F_XGM_CALFAULT    V_XGM_CALFAULT(1U)
+
+#define S_CALIMP    24
+#define M_CALIMP    0x1f
+#define V_CALIMP(x) ((x) << S_CALIMP)
+#define G_CALIMP(x) (((x) >> S_CALIMP) & M_CALIMP)
+
+#define S_XAUIIMP    0
+#define M_XAUIIMP    0x7
+#define V_XAUIIMP(x) ((x) << S_XAUIIMP)
+
+#define A_XGM_RX_MAX_PKT_SIZE 0x8a8
+#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4
+
+#define A_XGM_RESET_CTRL 0x8ac
+
+#define S_XG2G_RESET_    3
+#define V_XG2G_RESET_(x) ((x) << S_XG2G_RESET_)
+#define F_XG2G_RESET_    V_XG2G_RESET_(1U)
+
+#define S_RGMII_RESET_    2
+#define V_RGMII_RESET_(x) ((x) << S_RGMII_RESET_)
+#define F_RGMII_RESET_    V_RGMII_RESET_(1U)
+
+#define S_PCS_RESET_    1
+#define V_PCS_RESET_(x) ((x) << S_PCS_RESET_)
+#define F_PCS_RESET_    V_PCS_RESET_(1U)
+
+#define S_MAC_RESET_    0
+#define V_MAC_RESET_(x) ((x) << S_MAC_RESET_)
+#define F_MAC_RESET_    V_MAC_RESET_(1U)
+
+#define A_XGM_PORT_CFG 0x8b8
+
+#define S_CLKDIVRESET_    3
+#define V_CLKDIVRESET_(x) ((x) << S_CLKDIVRESET_)
+#define F_CLKDIVRESET_    V_CLKDIVRESET_(1U)
+
+#define S_PORTSPEED    1
+#define M_PORTSPEED    0x3
+
+#define V_PORTSPEED(x) ((x) << S_PORTSPEED)
+
+#define S_ENRGMII    0
+#define V_ENRGMII(x) ((x) << S_ENRGMII)
+#define F_ENRGMII    V_ENRGMII(1U)
+
+#define A_XGM_INT_ENABLE 0x8d4
+
+#define S_TXFIFO_PRTY_ERR    17
+#define M_TXFIFO_PRTY_ERR    0x7
+
+#define V_TXFIFO_PRTY_ERR(x) ((x) << S_TXFIFO_PRTY_ERR)
+
+#define S_RXFIFO_PRTY_ERR    14
+#define M_RXFIFO_PRTY_ERR    0x7
+
+#define V_RXFIFO_PRTY_ERR(x) ((x) << S_RXFIFO_PRTY_ERR)
+
+#define S_TXFIFO_UNDERRUN    13
+#define V_TXFIFO_UNDERRUN(x) ((x) << S_TXFIFO_UNDERRUN)
+#define F_TXFIFO_UNDERRUN    V_TXFIFO_UNDERRUN(1U)
+
+#define S_RXFIFO_OVERFLOW    12
+#define V_RXFIFO_OVERFLOW(x) ((x) << S_RXFIFO_OVERFLOW)
+#define F_RXFIFO_OVERFLOW    V_RXFIFO_OVERFLOW(1U)
+
+#define S_SERDES_LOS    4
+#define M_SERDES_LOS    0xf
+
+#define V_SERDES_LOS(x) ((x) << S_SERDES_LOS)
+
+#define S_XAUIPCSCTCERR    3
+#define V_XAUIPCSCTCERR(x) ((x) << S_XAUIPCSCTCERR)
+#define F_XAUIPCSCTCERR    V_XAUIPCSCTCERR(1U)
+
+#define S_XAUIPCSALIGNCHANGE    2
+#define V_XAUIPCSALIGNCHANGE(x) ((x) << S_XAUIPCSALIGNCHANGE)
+#define F_XAUIPCSALIGNCHANGE    V_XAUIPCSALIGNCHANGE(1U)
+
+#define A_XGM_INT_CAUSE 0x8d8
+
+#define A_XGM_XAUI_ACT_CTRL 0x8dc
+
+#define S_TXACTENABLE    1
+#define V_TXACTENABLE(x) ((x) << S_TXACTENABLE)
+#define F_TXACTENABLE    V_TXACTENABLE(1U)
+
+#define A_XGM_SERDES_CTRL0 0x8e0
+
+#define S_RESET3    23
+#define V_RESET3(x) ((x) << S_RESET3)
+#define F_RESET3    V_RESET3(1U)
+
+#define S_RESET2    22
+#define V_RESET2(x) ((x) << S_RESET2)
+#define F_RESET2    V_RESET2(1U)
+
+#define S_RESET1    21
+#define V_RESET1(x) ((x) << S_RESET1)
+#define F_RESET1    V_RESET1(1U)
+
+#define S_RESET0    20
+#define V_RESET0(x) ((x) << S_RESET0)
+#define F_RESET0    V_RESET0(1U)
+
+#define S_PWRDN3    19
+#define V_PWRDN3(x) ((x) << S_PWRDN3)
+#define F_PWRDN3    V_PWRDN3(1U)
+
+#define S_PWRDN2    18
+#define V_PWRDN2(x) ((x) << S_PWRDN2)
+#define F_PWRDN2    V_PWRDN2(1U)
+
+#define S_PWRDN1    17
+#define V_PWRDN1(x) ((x) << S_PWRDN1)
+#define F_PWRDN1    V_PWRDN1(1U)
+
+#define S_PWRDN0    16
+#define V_PWRDN0(x) ((x) << S_PWRDN0)
+#define F_PWRDN0    V_PWRDN0(1U)
+
+#define S_RESETPLL23    15
+#define V_RESETPLL23(x) ((x) << S_RESETPLL23)
+#define F_RESETPLL23    V_RESETPLL23(1U)
+
+#define S_RESETPLL01    14
+#define V_RESETPLL01(x) ((x) << S_RESETPLL01)
+#define F_RESETPLL01    V_RESETPLL01(1U)
+
+#define A_XGM_SERDES_STAT0 0x8f0
+
+#define S_LOWSIG0    0
+#define V_LOWSIG0(x) ((x) << S_LOWSIG0)
+#define F_LOWSIG0    V_LOWSIG0(1U)
+
+#define A_XGM_SERDES_STAT3 0x8fc
+
+#define A_XGM_STAT_TX_BYTE_LOW 0x900
+
+#define A_XGM_STAT_TX_BYTE_HIGH 0x904
+
+#define A_XGM_STAT_TX_FRAME_LOW 0x908
+
+#define A_XGM_STAT_TX_FRAME_HIGH 0x90c
+
+#define A_XGM_STAT_TX_BCAST 0x910
+
+#define A_XGM_STAT_TX_MCAST 0x914
+
+#define A_XGM_STAT_TX_PAUSE 0x918
+
+#define A_XGM_STAT_TX_64B_FRAMES 0x91c
+
+#define A_XGM_STAT_TX_65_127B_FRAMES 0x920
+
+#define A_XGM_STAT_TX_128_255B_FRAMES 0x924
+
+#define A_XGM_STAT_TX_256_511B_FRAMES 0x928
+
+#define A_XGM_STAT_TX_512_1023B_FRAMES 0x92c
+
+#define A_XGM_STAT_TX_1024_1518B_FRAMES 0x930
+
+#define A_XGM_STAT_TX_1519_MAXB_FRAMES 0x934
+
+#define A_XGM_STAT_TX_ERR_FRAMES 0x938
+
+#define A_XGM_STAT_RX_BYTES_LOW 0x93c
+
+#define A_XGM_STAT_RX_BYTES_HIGH 0x940
+
+#define A_XGM_STAT_RX_FRAMES_LOW 0x944
+
+#define A_XGM_STAT_RX_FRAMES_HIGH 0x948
+
+#define A_XGM_STAT_RX_BCAST_FRAMES 0x94c
+
+#define A_XGM_STAT_RX_MCAST_FRAMES 0x950
+
+#define A_XGM_STAT_RX_PAUSE_FRAMES 0x954
+
+#define A_XGM_STAT_RX_64B_FRAMES 0x958
+
+#define A_XGM_STAT_RX_65_127B_FRAMES 0x95c
+
+#define A_XGM_STAT_RX_128_255B_FRAMES 0x960
+
+#define A_XGM_STAT_RX_256_511B_FRAMES 0x964
+
+#define A_XGM_STAT_RX_512_1023B_FRAMES 0x968
+
+#define A_XGM_STAT_RX_1024_1518B_FRAMES 0x96c
+
+#define A_XGM_STAT_RX_1519_MAXB_FRAMES 0x970
+
+#define A_XGM_STAT_RX_SHORT_FRAMES 0x974
+
+#define A_XGM_STAT_RX_OVERSIZE_FRAMES 0x978
+
+#define A_XGM_STAT_RX_JABBER_FRAMES 0x97c
+
+#define A_XGM_STAT_RX_CRC_ERR_FRAMES 0x980
+
+#define A_XGM_STAT_RX_LENGTH_ERR_FRAMES 0x984
+
+#define A_XGM_STAT_RX_SYM_CODE_ERR_FRAMES 0x988
+
+#define A_XGM_SERDES_STATUS0 0x98c
+
+#define A_XGM_SERDES_STATUS1 0x990
+
+#define S_CMULOCK    31
+#define V_CMULOCK(x) ((x) << S_CMULOCK)
+#define F_CMULOCK    V_CMULOCK(1U)
+
+#define A_XGM_RX_MAX_PKT_SIZE_ERR_CNT 0x9a4
+
+#define A_XGM_RX_SPI4_SOP_EOP_CNT 0x9ac
+
+#define XGMAC0_1_BASE_ADDR 0xa00
diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c
new file mode 100644 (file)
index 0000000..3f2cf8a
--- /dev/null
@@ -0,0 +1,2681 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/dma-mapping.h>
+#include "common.h"
+#include "regs.h"
+#include "sge_defs.h"
+#include "t3_cpl.h"
+#include "firmware_exports.h"
+
+#define USE_GTS 0
+
+#define SGE_RX_SM_BUF_SIZE 1536
+#define SGE_RX_COPY_THRES  256
+
+# define SGE_RX_DROP_THRES 16
+
+/*
+ * Period of the Tx buffer reclaim timer.  This timer does not need to run
+ * frequently as Tx buffers are usually reclaimed by new Tx packets.
+ */
+#define TX_RECLAIM_PERIOD (HZ / 4)
+
+/* WR size in bytes */
+#define WR_LEN (WR_FLITS * 8)
+
+/*
+ * Types of Tx queues in each queue set.  Order here matters, do not change.
+ */
+enum { TXQ_ETH, TXQ_OFLD, TXQ_CTRL };
+
+/* Values for sge_txq.flags */
+enum {
+       TXQ_RUNNING = 1 << 0,   /* fetch engine is running */
+       TXQ_LAST_PKT_DB = 1 << 1,       /* last packet rang the doorbell */
+};
+
+struct tx_desc {
+       u64 flit[TX_DESC_FLITS];
+};
+
+struct rx_desc {
+       __be32 addr_lo;
+       __be32 len_gen;
+       __be32 gen2;
+       __be32 addr_hi;
+};
+
+struct tx_sw_desc {            /* SW state per Tx descriptor */
+       struct sk_buff *skb;
+};
+
+struct rx_sw_desc {            /* SW state per Rx descriptor */
+       struct sk_buff *skb;
+        DECLARE_PCI_UNMAP_ADDR(dma_addr);
+};
+
+struct rsp_desc {              /* response queue descriptor */
+       struct rss_header rss_hdr;
+       __be32 flags;
+       __be32 len_cq;
+       u8 imm_data[47];
+       u8 intr_gen;
+};
+
+struct unmap_info {            /* packet unmapping info, overlays skb->cb */
+       int sflit;              /* start flit of first SGL entry in Tx descriptor */
+       u16 fragidx;            /* first page fragment in current Tx descriptor */
+       u16 addr_idx;           /* buffer index of first SGL entry in descriptor */
+       u32 len;                /* mapped length of skb main body */
+};
+
+/*
+ * Maps a number of flits to the number of Tx descriptors that can hold them.
+ * The formula is
+ *
+ * desc = 1 + (flits - 2) / (WR_FLITS - 1).
+ *
+ * HW allows up to 4 descriptors to be combined into a WR.
+ */
+static u8 flit_desc_map[] = {
+       0,
+#if SGE_NUM_GENBITS == 1
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4
+#elif SGE_NUM_GENBITS == 2
+       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+       3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+       4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+#else
+# error "SGE_NUM_GENBITS must be 1 or 2"
+#endif
+};
+
+static inline struct sge_qset *fl_to_qset(const struct sge_fl *q, int qidx)
+{
+       return container_of(q, struct sge_qset, fl[qidx]);
+}
+
+static inline struct sge_qset *rspq_to_qset(const struct sge_rspq *q)
+{
+       return container_of(q, struct sge_qset, rspq);
+}
+
+static inline struct sge_qset *txq_to_qset(const struct sge_txq *q, int qidx)
+{
+       return container_of(q, struct sge_qset, txq[qidx]);
+}
+
+/**
+ *     refill_rspq - replenish an SGE response queue
+ *     @adapter: the adapter
+ *     @q: the response queue to replenish
+ *     @credits: how many new responses to make available
+ *
+ *     Replenishes a response queue by making the supplied number of responses
+ *     available to HW.
+ */
+static inline void refill_rspq(struct adapter *adapter,
+                              const struct sge_rspq *q, unsigned int credits)
+{
+       t3_write_reg(adapter, A_SG_RSPQ_CREDIT_RETURN,
+                    V_RSPQ(q->cntxt_id) | V_CREDITS(credits));
+}
+
+/**
+ *     need_skb_unmap - does the platform need unmapping of sk_buffs?
+ *
+ *     Returns true if the platfrom needs sk_buff unmapping.  The compiler
+ *     optimizes away unecessary code if this returns true.
+ */
+static inline int need_skb_unmap(void)
+{
+       /*
+        * This structure is used to tell if the platfrom needs buffer
+        * unmapping by checking if DECLARE_PCI_UNMAP_ADDR defines anything.
+        */
+       struct dummy {
+               DECLARE_PCI_UNMAP_ADDR(addr);
+       };
+
+       return sizeof(struct dummy) != 0;
+}
+
+/**
+ *     unmap_skb - unmap a packet main body and its page fragments
+ *     @skb: the packet
+ *     @q: the Tx queue containing Tx descriptors for the packet
+ *     @cidx: index of Tx descriptor
+ *     @pdev: the PCI device
+ *
+ *     Unmap the main body of an sk_buff and its page fragments, if any.
+ *     Because of the fairly complicated structure of our SGLs and the desire
+ *     to conserve space for metadata, we keep the information necessary to
+ *     unmap an sk_buff partly in the sk_buff itself (in its cb), and partly
+ *     in the Tx descriptors (the physical addresses of the various data
+ *     buffers).  The send functions initialize the state in skb->cb so we
+ *     can unmap the buffers held in the first Tx descriptor here, and we
+ *     have enough information at this point to update the state for the next
+ *     Tx descriptor.
+ */
+static inline void unmap_skb(struct sk_buff *skb, struct sge_txq *q,
+                            unsigned int cidx, struct pci_dev *pdev)
+{
+       const struct sg_ent *sgp;
+       struct unmap_info *ui = (struct unmap_info *)skb->cb;
+       int nfrags, frag_idx, curflit, j = ui->addr_idx;
+
+       sgp = (struct sg_ent *)&q->desc[cidx].flit[ui->sflit];
+
+       if (ui->len) {
+               pci_unmap_single(pdev, be64_to_cpu(sgp->addr[0]), ui->len,
+                                PCI_DMA_TODEVICE);
+               ui->len = 0;    /* so we know for next descriptor for this skb */
+               j = 1;
+       }
+
+       frag_idx = ui->fragidx;
+       curflit = ui->sflit + 1 + j;
+       nfrags = skb_shinfo(skb)->nr_frags;
+
+       while (frag_idx < nfrags && curflit < WR_FLITS) {
+               pci_unmap_page(pdev, be64_to_cpu(sgp->addr[j]),
+                              skb_shinfo(skb)->frags[frag_idx].size,
+                              PCI_DMA_TODEVICE);
+               j ^= 1;
+               if (j == 0) {
+                       sgp++;
+                       curflit++;
+               }
+               curflit++;
+               frag_idx++;
+       }
+
+       if (frag_idx < nfrags) {        /* SGL continues into next Tx descriptor */
+               ui->fragidx = frag_idx;
+               ui->addr_idx = j;
+               ui->sflit = curflit - WR_FLITS - j;     /* sflit can be -1 */
+       }
+}
+
+/**
+ *     free_tx_desc - reclaims Tx descriptors and their buffers
+ *     @adapter: the adapter
+ *     @q: the Tx queue to reclaim descriptors from
+ *     @n: the number of descriptors to reclaim
+ *
+ *     Reclaims Tx descriptors from an SGE Tx queue and frees the associated
+ *     Tx buffers.  Called with the Tx queue lock held.
+ */
+static void free_tx_desc(struct adapter *adapter, struct sge_txq *q,
+                        unsigned int n)
+{
+       struct tx_sw_desc *d;
+       struct pci_dev *pdev = adapter->pdev;
+       unsigned int cidx = q->cidx;
+
+       d = &q->sdesc[cidx];
+       while (n--) {
+               if (d->skb) {   /* an SGL is present */
+                       if (need_skb_unmap())
+                               unmap_skb(d->skb, q, cidx, pdev);
+                       if (d->skb->priority == cidx)
+                               kfree_skb(d->skb);
+               }
+               ++d;
+               if (++cidx == q->size) {
+                       cidx = 0;
+                       d = q->sdesc;
+               }
+       }
+       q->cidx = cidx;
+}
+
+/**
+ *     reclaim_completed_tx - reclaims completed Tx descriptors
+ *     @adapter: the adapter
+ *     @q: the Tx queue to reclaim completed descriptors from
+ *
+ *     Reclaims Tx descriptors that the SGE has indicated it has processed,
+ *     and frees the associated buffers if possible.  Called with the Tx
+ *     queue's lock held.
+ */
+static inline void reclaim_completed_tx(struct adapter *adapter,
+                                       struct sge_txq *q)
+{
+       unsigned int reclaim = q->processed - q->cleaned;
+
+       if (reclaim) {
+               free_tx_desc(adapter, q, reclaim);
+               q->cleaned += reclaim;
+               q->in_use -= reclaim;
+       }
+}
+
+/**
+ *     should_restart_tx - are there enough resources to restart a Tx queue?
+ *     @q: the Tx queue
+ *
+ *     Checks if there are enough descriptors to restart a suspended Tx queue.
+ */
+static inline int should_restart_tx(const struct sge_txq *q)
+{
+       unsigned int r = q->processed - q->cleaned;
+
+       return q->in_use - r < (q->size >> 1);
+}
+
+/**
+ *     free_rx_bufs - free the Rx buffers on an SGE free list
+ *     @pdev: the PCI device associated with the adapter
+ *     @rxq: the SGE free list to clean up
+ *
+ *     Release the buffers on an SGE free-buffer Rx queue.  HW fetching from
+ *     this queue should be stopped before calling this function.
+ */
+static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
+{
+       unsigned int cidx = q->cidx;
+
+       while (q->credits--) {
+               struct rx_sw_desc *d = &q->sdesc[cidx];
+
+               pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr),
+                                q->buf_size, PCI_DMA_FROMDEVICE);
+               kfree_skb(d->skb);
+               d->skb = NULL;
+               if (++cidx == q->size)
+                       cidx = 0;
+       }
+}
+
+/**
+ *     add_one_rx_buf - add a packet buffer to a free-buffer list
+ *     @skb: the buffer to add
+ *     @len: the buffer length
+ *     @d: the HW Rx descriptor to write
+ *     @sd: the SW Rx descriptor to write
+ *     @gen: the generation bit value
+ *     @pdev: the PCI device associated with the adapter
+ *
+ *     Add a buffer of the given length to the supplied HW and SW Rx
+ *     descriptors.
+ */
+static inline void add_one_rx_buf(struct sk_buff *skb, unsigned int len,
+                                 struct rx_desc *d, struct rx_sw_desc *sd,
+                                 unsigned int gen, struct pci_dev *pdev)
+{
+       dma_addr_t mapping;
+
+       sd->skb = skb;
+       mapping = pci_map_single(pdev, skb->data, len, PCI_DMA_FROMDEVICE);
+       pci_unmap_addr_set(sd, dma_addr, mapping);
+
+       d->addr_lo = cpu_to_be32(mapping);
+       d->addr_hi = cpu_to_be32((u64) mapping >> 32);
+       wmb();
+       d->len_gen = cpu_to_be32(V_FLD_GEN1(gen));
+       d->gen2 = cpu_to_be32(V_FLD_GEN2(gen));
+}
+
+/**
+ *     refill_fl - refill an SGE free-buffer list
+ *     @adapter: the adapter
+ *     @q: the free-list to refill
+ *     @n: the number of new buffers to allocate
+ *     @gfp: the gfp flags for allocating new buffers
+ *
+ *     (Re)populate an SGE free-buffer list with up to @n new packet buffers,
+ *     allocated with the supplied gfp flags.  The caller must assure that
+ *     @n does not exceed the queue's capacity.
+ */
+static void refill_fl(struct adapter *adap, struct sge_fl *q, int n, gfp_t gfp)
+{
+       struct rx_sw_desc *sd = &q->sdesc[q->pidx];
+       struct rx_desc *d = &q->desc[q->pidx];
+
+       while (n--) {
+               struct sk_buff *skb = alloc_skb(q->buf_size, gfp);
+
+               if (!skb)
+                       break;
+
+               add_one_rx_buf(skb, q->buf_size, d, sd, q->gen, adap->pdev);
+               d++;
+               sd++;
+               if (++q->pidx == q->size) {
+                       q->pidx = 0;
+                       q->gen ^= 1;
+                       sd = q->sdesc;
+                       d = q->desc;
+               }
+               q->credits++;
+       }
+
+       t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+}
+
+static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl)
+{
+       refill_fl(adap, fl, min(16U, fl->size - fl->credits), GFP_ATOMIC);
+}
+
+/**
+ *     recycle_rx_buf - recycle a receive buffer
+ *     @adapter: the adapter
+ *     @q: the SGE free list
+ *     @idx: index of buffer to recycle
+ *
+ *     Recycles the specified buffer on the given free list by adding it at
+ *     the next available slot on the list.
+ */
+static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q,
+                          unsigned int idx)
+{
+       struct rx_desc *from = &q->desc[idx];
+       struct rx_desc *to = &q->desc[q->pidx];
+
+       q->sdesc[q->pidx] = q->sdesc[idx];
+       to->addr_lo = from->addr_lo;    /* already big endian */
+       to->addr_hi = from->addr_hi;    /* likewise */
+       wmb();
+       to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen));
+       to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen));
+       q->credits++;
+
+       if (++q->pidx == q->size) {
+               q->pidx = 0;
+               q->gen ^= 1;
+       }
+       t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+}
+
+/**
+ *     alloc_ring - allocate resources for an SGE descriptor ring
+ *     @pdev: the PCI device
+ *     @nelem: the number of descriptors
+ *     @elem_size: the size of each descriptor
+ *     @sw_size: the size of the SW state associated with each ring element
+ *     @phys: the physical address of the allocated ring
+ *     @metadata: address of the array holding the SW state for the ring
+ *
+ *     Allocates resources for an SGE descriptor ring, such as Tx queues,
+ *     free buffer lists, or response queues.  Each SGE ring requires
+ *     space for its HW descriptors plus, optionally, space for the SW state
+ *     associated with each HW entry (the metadata).  The function returns
+ *     three values: the virtual address for the HW ring (the return value
+ *     of the function), the physical address of the HW ring, and the address
+ *     of the SW ring.
+ */
+static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size,
+                       size_t sw_size, dma_addr_t *phys, void *metadata)
+{
+       size_t len = nelem * elem_size;
+       void *s = NULL;
+       void *p = dma_alloc_coherent(&pdev->dev, len, phys, GFP_KERNEL);
+
+       if (!p)
+               return NULL;
+       if (sw_size) {
+               s = kcalloc(nelem, sw_size, GFP_KERNEL);
+
+               if (!s) {
+                       dma_free_coherent(&pdev->dev, len, p, *phys);
+                       return NULL;
+               }
+       }
+       if (metadata)
+               *(void **)metadata = s;
+       memset(p, 0, len);
+       return p;
+}
+
+/**
+ *     free_qset - free the resources of an SGE queue set
+ *     @adapter: the adapter owning the queue set
+ *     @q: the queue set
+ *
+ *     Release the HW and SW resources associated with an SGE queue set, such
+ *     as HW contexts, packet buffers, and descriptor rings.  Traffic to the
+ *     queue set must be quiesced prior to calling this.
+ */
+void t3_free_qset(struct adapter *adapter, struct sge_qset *q)
+{
+       int i;
+       struct pci_dev *pdev = adapter->pdev;
+
+       if (q->tx_reclaim_timer.function)
+               del_timer_sync(&q->tx_reclaim_timer);
+
+       for (i = 0; i < SGE_RXQ_PER_SET; ++i)
+               if (q->fl[i].desc) {
+                       spin_lock(&adapter->sge.reg_lock);
+                       t3_sge_disable_fl(adapter, q->fl[i].cntxt_id);
+                       spin_unlock(&adapter->sge.reg_lock);
+                       free_rx_bufs(pdev, &q->fl[i]);
+                       kfree(q->fl[i].sdesc);
+                       dma_free_coherent(&pdev->dev,
+                                         q->fl[i].size *
+                                         sizeof(struct rx_desc), q->fl[i].desc,
+                                         q->fl[i].phys_addr);
+               }
+
+       for (i = 0; i < SGE_TXQ_PER_SET; ++i)
+               if (q->txq[i].desc) {
+                       spin_lock(&adapter->sge.reg_lock);
+                       t3_sge_enable_ecntxt(adapter, q->txq[i].cntxt_id, 0);
+                       spin_unlock(&adapter->sge.reg_lock);
+                       if (q->txq[i].sdesc) {
+                               free_tx_desc(adapter, &q->txq[i],
+                                            q->txq[i].in_use);
+                               kfree(q->txq[i].sdesc);
+                       }
+                       dma_free_coherent(&pdev->dev,
+                                         q->txq[i].size *
+                                         sizeof(struct tx_desc),
+                                         q->txq[i].desc, q->txq[i].phys_addr);
+                       __skb_queue_purge(&q->txq[i].sendq);
+               }
+
+       if (q->rspq.desc) {
+               spin_lock(&adapter->sge.reg_lock);
+               t3_sge_disable_rspcntxt(adapter, q->rspq.cntxt_id);
+               spin_unlock(&adapter->sge.reg_lock);
+               dma_free_coherent(&pdev->dev,
+                                 q->rspq.size * sizeof(struct rsp_desc),
+                                 q->rspq.desc, q->rspq.phys_addr);
+       }
+
+       if (q->netdev)
+               q->netdev->atalk_ptr = NULL;
+
+       memset(q, 0, sizeof(*q));
+}
+
+/**
+ *     init_qset_cntxt - initialize an SGE queue set context info
+ *     @qs: the queue set
+ *     @id: the queue set id
+ *
+ *     Initializes the TIDs and context ids for the queues of a queue set.
+ */
+static void init_qset_cntxt(struct sge_qset *qs, unsigned int id)
+{
+       qs->rspq.cntxt_id = id;
+       qs->fl[0].cntxt_id = 2 * id;
+       qs->fl[1].cntxt_id = 2 * id + 1;
+       qs->txq[TXQ_ETH].cntxt_id = FW_TUNNEL_SGEEC_START + id;
+       qs->txq[TXQ_ETH].token = FW_TUNNEL_TID_START + id;
+       qs->txq[TXQ_OFLD].cntxt_id = FW_OFLD_SGEEC_START + id;
+       qs->txq[TXQ_CTRL].cntxt_id = FW_CTRL_SGEEC_START + id;
+       qs->txq[TXQ_CTRL].token = FW_CTRL_TID_START + id;
+}
+
+/**
+ *     sgl_len - calculates the size of an SGL of the given capacity
+ *     @n: the number of SGL entries
+ *
+ *     Calculates the number of flits needed for a scatter/gather list that
+ *     can hold the given number of entries.
+ */
+static inline unsigned int sgl_len(unsigned int n)
+{
+       /* alternatively: 3 * (n / 2) + 2 * (n & 1) */
+       return (3 * n) / 2 + (n & 1);
+}
+
+/**
+ *     flits_to_desc - returns the num of Tx descriptors for the given flits
+ *     @n: the number of flits
+ *
+ *     Calculates the number of Tx descriptors needed for the supplied number
+ *     of flits.
+ */
+static inline unsigned int flits_to_desc(unsigned int n)
+{
+       BUG_ON(n >= ARRAY_SIZE(flit_desc_map));
+       return flit_desc_map[n];
+}
+
+/**
+ *     get_packet - return the next ingress packet buffer from a free list
+ *     @adap: the adapter that received the packet
+ *     @fl: the SGE free list holding the packet
+ *     @len: the packet length including any SGE padding
+ *     @drop_thres: # of remaining buffers before we start dropping packets
+ *
+ *     Get the next packet from a free list and complete setup of the
+ *     sk_buff.  If the packet is small we make a copy and recycle the
+ *     original buffer, otherwise we use the original buffer itself.  If a
+ *     positive drop threshold is supplied packets are dropped and their
+ *     buffers recycled if (a) the number of remaining buffers is under the
+ *     threshold and the packet is too big to copy, or (b) the packet should
+ *     be copied but there is no memory for the copy.
+ */
+static struct sk_buff *get_packet(struct adapter *adap, struct sge_fl *fl,
+                                 unsigned int len, unsigned int drop_thres)
+{
+       struct sk_buff *skb = NULL;
+       struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
+
+       prefetch(sd->skb->data);
+
+       if (len <= SGE_RX_COPY_THRES) {
+               skb = alloc_skb(len, GFP_ATOMIC);
+               if (likely(skb != NULL)) {
+                       __skb_put(skb, len);
+                       pci_dma_sync_single_for_cpu(adap->pdev,
+                                                   pci_unmap_addr(sd,
+                                                                  dma_addr),
+                                                   len, PCI_DMA_FROMDEVICE);
+                       memcpy(skb->data, sd->skb->data, len);
+                       pci_dma_sync_single_for_device(adap->pdev,
+                                                      pci_unmap_addr(sd,
+                                                                     dma_addr),
+                                                      len, PCI_DMA_FROMDEVICE);
+               } else if (!drop_thres)
+                       goto use_orig_buf;
+             recycle:
+               recycle_rx_buf(adap, fl, fl->cidx);
+               return skb;
+       }
+
+       if (unlikely(fl->credits < drop_thres))
+               goto recycle;
+
+      use_orig_buf:
+       pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
+                        fl->buf_size, PCI_DMA_FROMDEVICE);
+       skb = sd->skb;
+       skb_put(skb, len);
+       __refill_fl(adap, fl);
+       return skb;
+}
+
+/**
+ *     get_imm_packet - return the next ingress packet buffer from a response
+ *     @resp: the response descriptor containing the packet data
+ *
+ *     Return a packet containing the immediate data of the given response.
+ */
+static inline struct sk_buff *get_imm_packet(const struct rsp_desc *resp)
+{
+       struct sk_buff *skb = alloc_skb(IMMED_PKT_SIZE, GFP_ATOMIC);
+
+       if (skb) {
+               __skb_put(skb, IMMED_PKT_SIZE);
+               memcpy(skb->data, resp->imm_data, IMMED_PKT_SIZE);
+       }
+       return skb;
+}
+
+/**
+ *     calc_tx_descs - calculate the number of Tx descriptors for a packet
+ *     @skb: the packet
+ *
+ *     Returns the number of Tx descriptors needed for the given Ethernet
+ *     packet.  Ethernet packets require addition of WR and CPL headers.
+ */
+static inline unsigned int calc_tx_descs(const struct sk_buff *skb)
+{
+       unsigned int flits;
+
+       if (skb->len <= WR_LEN - sizeof(struct cpl_tx_pkt))
+               return 1;
+
+       flits = sgl_len(skb_shinfo(skb)->nr_frags + 1) + 2;
+       if (skb_shinfo(skb)->gso_size)
+               flits++;
+       return flits_to_desc(flits);
+}
+
+/**
+ *     make_sgl - populate a scatter/gather list for a packet
+ *     @skb: the packet
+ *     @sgp: the SGL to populate
+ *     @start: start address of skb main body data to include in the SGL
+ *     @len: length of skb main body data to include in the SGL
+ *     @pdev: the PCI device
+ *
+ *     Generates a scatter/gather list for the buffers that make up a packet
+ *     and returns the SGL size in 8-byte words.  The caller must size the SGL
+ *     appropriately.
+ */
+static inline unsigned int make_sgl(const struct sk_buff *skb,
+                                   struct sg_ent *sgp, unsigned char *start,
+                                   unsigned int len, struct pci_dev *pdev)
+{
+       dma_addr_t mapping;
+       unsigned int i, j = 0, nfrags;
+
+       if (len) {
+               mapping = pci_map_single(pdev, start, len, PCI_DMA_TODEVICE);
+               sgp->len[0] = cpu_to_be32(len);
+               sgp->addr[0] = cpu_to_be64(mapping);
+               j = 1;
+       }
+
+       nfrags = skb_shinfo(skb)->nr_frags;
+       for (i = 0; i < nfrags; i++) {
+               skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+               mapping = pci_map_page(pdev, frag->page, frag->page_offset,
+                                      frag->size, PCI_DMA_TODEVICE);
+               sgp->len[j] = cpu_to_be32(frag->size);
+               sgp->addr[j] = cpu_to_be64(mapping);
+               j ^= 1;
+               if (j == 0)
+                       ++sgp;
+       }
+       if (j)
+               sgp->len[j] = 0;
+       return ((nfrags + (len != 0)) * 3) / 2 + j;
+}
+
+/**
+ *     check_ring_tx_db - check and potentially ring a Tx queue's doorbell
+ *     @adap: the adapter
+ *     @q: the Tx queue
+ *
+ *     Ring the doorbel if a Tx queue is asleep.  There is a natural race,
+ *     where the HW is going to sleep just after we checked, however,
+ *     then the interrupt handler will detect the outstanding TX packet
+ *     and ring the doorbell for us.
+ *
+ *     When GTS is disabled we unconditionally ring the doorbell.
+ */
+static inline void check_ring_tx_db(struct adapter *adap, struct sge_txq *q)
+{
+#if USE_GTS
+       clear_bit(TXQ_LAST_PKT_DB, &q->flags);
+       if (test_and_set_bit(TXQ_RUNNING, &q->flags) == 0) {
+               set_bit(TXQ_LAST_PKT_DB, &q->flags);
+               t3_write_reg(adap, A_SG_KDOORBELL,
+                            F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+       }
+#else
+       wmb();                  /* write descriptors before telling HW */
+       t3_write_reg(adap, A_SG_KDOORBELL,
+                    F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+#endif
+}
+
+static inline void wr_gen2(struct tx_desc *d, unsigned int gen)
+{
+#if SGE_NUM_GENBITS == 2
+       d->flit[TX_DESC_FLITS - 1] = cpu_to_be64(gen);
+#endif
+}
+
+/**
+ *     write_wr_hdr_sgl - write a WR header and, optionally, SGL
+ *     @ndesc: number of Tx descriptors spanned by the SGL
+ *     @skb: the packet corresponding to the WR
+ *     @d: first Tx descriptor to be written
+ *     @pidx: index of above descriptors
+ *     @q: the SGE Tx queue
+ *     @sgl: the SGL
+ *     @flits: number of flits to the start of the SGL in the first descriptor
+ *     @sgl_flits: the SGL size in flits
+ *     @gen: the Tx descriptor generation
+ *     @wr_hi: top 32 bits of WR header based on WR type (big endian)
+ *     @wr_lo: low 32 bits of WR header based on WR type (big endian)
+ *
+ *     Write a work request header and an associated SGL.  If the SGL is
+ *     small enough to fit into one Tx descriptor it has already been written
+ *     and we just need to write the WR header.  Otherwise we distribute the
+ *     SGL across the number of descriptors it spans.
+ */
+static void write_wr_hdr_sgl(unsigned int ndesc, struct sk_buff *skb,
+                            struct tx_desc *d, unsigned int pidx,
+                            const struct sge_txq *q,
+                            const struct sg_ent *sgl,
+                            unsigned int flits, unsigned int sgl_flits,
+                            unsigned int gen, unsigned int wr_hi,
+                            unsigned int wr_lo)
+{
+       struct work_request_hdr *wrp = (struct work_request_hdr *)d;
+       struct tx_sw_desc *sd = &q->sdesc[pidx];
+
+       sd->skb = skb;
+       if (need_skb_unmap()) {
+               struct unmap_info *ui = (struct unmap_info *)skb->cb;
+
+               ui->fragidx = 0;
+               ui->addr_idx = 0;
+               ui->sflit = flits;
+       }
+
+       if (likely(ndesc == 1)) {
+               skb->priority = pidx;
+               wrp->wr_hi = htonl(F_WR_SOP | F_WR_EOP | V_WR_DATATYPE(1) |
+                                  V_WR_SGLSFLT(flits)) | wr_hi;
+               wmb();
+               wrp->wr_lo = htonl(V_WR_LEN(flits + sgl_flits) |
+                                  V_WR_GEN(gen)) | wr_lo;
+               wr_gen2(d, gen);
+       } else {
+               unsigned int ogen = gen;
+               const u64 *fp = (const u64 *)sgl;
+               struct work_request_hdr *wp = wrp;
+
+               wrp->wr_hi = htonl(F_WR_SOP | V_WR_DATATYPE(1) |
+                                  V_WR_SGLSFLT(flits)) | wr_hi;
+
+               while (sgl_flits) {
+                       unsigned int avail = WR_FLITS - flits;
+
+                       if (avail > sgl_flits)
+                               avail = sgl_flits;
+                       memcpy(&d->flit[flits], fp, avail * sizeof(*fp));
+                       sgl_flits -= avail;
+                       ndesc--;
+                       if (!sgl_flits)
+                               break;
+
+                       fp += avail;
+                       d++;
+                       sd++;
+                       if (++pidx == q->size) {
+                               pidx = 0;
+                               gen ^= 1;
+                               d = q->desc;
+                               sd = q->sdesc;
+                       }
+
+                       sd->skb = skb;
+                       wrp = (struct work_request_hdr *)d;
+                       wrp->wr_hi = htonl(V_WR_DATATYPE(1) |
+                                          V_WR_SGLSFLT(1)) | wr_hi;
+                       wrp->wr_lo = htonl(V_WR_LEN(min(WR_FLITS,
+                                                       sgl_flits + 1)) |
+                                          V_WR_GEN(gen)) | wr_lo;
+                       wr_gen2(d, gen);
+                       flits = 1;
+               }
+               skb->priority = pidx;
+               wrp->wr_hi |= htonl(F_WR_EOP);
+               wmb();
+               wp->wr_lo = htonl(V_WR_LEN(WR_FLITS) | V_WR_GEN(ogen)) | wr_lo;
+               wr_gen2((struct tx_desc *)wp, ogen);
+               WARN_ON(ndesc != 0);
+       }
+}
+
+/**
+ *     write_tx_pkt_wr - write a TX_PKT work request
+ *     @adap: the adapter
+ *     @skb: the packet to send
+ *     @pi: the egress interface
+ *     @pidx: index of the first Tx descriptor to write
+ *     @gen: the generation value to use
+ *     @q: the Tx queue
+ *     @ndesc: number of descriptors the packet will occupy
+ *     @compl: the value of the COMPL bit to use
+ *
+ *     Generate a TX_PKT work request to send the supplied packet.
+ */
+static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
+                           const struct port_info *pi,
+                           unsigned int pidx, unsigned int gen,
+                           struct sge_txq *q, unsigned int ndesc,
+                           unsigned int compl)
+{
+       unsigned int flits, sgl_flits, cntrl, tso_info;
+       struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
+       struct tx_desc *d = &q->desc[pidx];
+       struct cpl_tx_pkt *cpl = (struct cpl_tx_pkt *)d;
+
+       cpl->len = htonl(skb->len | 0x80000000);
+       cntrl = V_TXPKT_INTF(pi->port_id);
+
+       if (vlan_tx_tag_present(skb) && pi->vlan_grp)
+               cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(vlan_tx_tag_get(skb));
+
+       tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size);
+       if (tso_info) {
+               int eth_type;
+               struct cpl_tx_pkt_lso *hdr = (struct cpl_tx_pkt_lso *)cpl;
+
+               d->flit[2] = 0;
+               cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT_LSO);
+               hdr->cntrl = htonl(cntrl);
+               eth_type = skb->nh.raw - skb->data == ETH_HLEN ?
+                   CPL_ETH_II : CPL_ETH_II_VLAN;
+               tso_info |= V_LSO_ETH_TYPE(eth_type) |
+                   V_LSO_IPHDR_WORDS(skb->nh.iph->ihl) |
+                   V_LSO_TCPHDR_WORDS(skb->h.th->doff);
+               hdr->lso_info = htonl(tso_info);
+               flits = 3;
+       } else {
+               cntrl |= V_TXPKT_OPCODE(CPL_TX_PKT);
+               cntrl |= F_TXPKT_IPCSUM_DIS;    /* SW calculates IP csum */
+               cntrl |= V_TXPKT_L4CSUM_DIS(skb->ip_summed != CHECKSUM_PARTIAL);
+               cpl->cntrl = htonl(cntrl);
+
+               if (skb->len <= WR_LEN - sizeof(*cpl)) {
+                       q->sdesc[pidx].skb = NULL;
+                       if (!skb->data_len)
+                               memcpy(&d->flit[2], skb->data, skb->len);
+                       else
+                               skb_copy_bits(skb, 0, &d->flit[2], skb->len);
+
+                       flits = (skb->len + 7) / 8 + 2;
+                       cpl->wr.wr_hi = htonl(V_WR_BCNTLFLT(skb->len & 7) |
+                                             V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT)
+                                             | F_WR_SOP | F_WR_EOP | compl);
+                       wmb();
+                       cpl->wr.wr_lo = htonl(V_WR_LEN(flits) | V_WR_GEN(gen) |
+                                             V_WR_TID(q->token));
+                       wr_gen2(d, gen);
+                       kfree_skb(skb);
+                       return;
+               }
+
+               flits = 2;
+       }
+
+       sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
+       sgl_flits = make_sgl(skb, sgp, skb->data, skb_headlen(skb), adap->pdev);
+       if (need_skb_unmap())
+               ((struct unmap_info *)skb->cb)->len = skb_headlen(skb);
+
+       write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits, gen,
+                        htonl(V_WR_OP(FW_WROPCODE_TUNNEL_TX_PKT) | compl),
+                        htonl(V_WR_TID(q->token)));
+}
+
+/**
+ *     eth_xmit - add a packet to the Ethernet Tx queue
+ *     @skb: the packet
+ *     @dev: the egress net device
+ *
+ *     Add a packet to an SGE Tx queue.  Runs with softirqs disabled.
+ */
+int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       unsigned int ndesc, pidx, credits, gen, compl;
+       const struct port_info *pi = netdev_priv(dev);
+       struct adapter *adap = dev->priv;
+       struct sge_qset *qs = dev2qset(dev);
+       struct sge_txq *q = &qs->txq[TXQ_ETH];
+
+       /*
+        * The chip min packet length is 9 octets but play safe and reject
+        * anything shorter than an Ethernet header.
+        */
+       if (unlikely(skb->len < ETH_HLEN)) {
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       spin_lock(&q->lock);
+       reclaim_completed_tx(adap, q);
+
+       credits = q->size - q->in_use;
+       ndesc = calc_tx_descs(skb);
+
+       if (unlikely(credits < ndesc)) {
+               if (!netif_queue_stopped(dev)) {
+                       netif_stop_queue(dev);
+                       set_bit(TXQ_ETH, &qs->txq_stopped);
+                       q->stops++;
+                       dev_err(&adap->pdev->dev,
+                               "%s: Tx ring %u full while queue awake!\n",
+                               dev->name, q->cntxt_id & 7);
+               }
+               spin_unlock(&q->lock);
+               return NETDEV_TX_BUSY;
+       }
+
+       q->in_use += ndesc;
+       if (unlikely(credits - ndesc < q->stop_thres)) {
+               q->stops++;
+               netif_stop_queue(dev);
+               set_bit(TXQ_ETH, &qs->txq_stopped);
+#if !USE_GTS
+               if (should_restart_tx(q) &&
+                   test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) {
+                       q->restarts++;
+                       netif_wake_queue(dev);
+               }
+#endif
+       }
+
+       gen = q->gen;
+       q->unacked += ndesc;
+       compl = (q->unacked & 8) << (S_WR_COMPL - 3);
+       q->unacked &= 7;
+       pidx = q->pidx;
+       q->pidx += ndesc;
+       if (q->pidx >= q->size) {
+               q->pidx -= q->size;
+               q->gen ^= 1;
+       }
+
+       /* update port statistics */
+       if (skb->ip_summed == CHECKSUM_COMPLETE)
+               qs->port_stats[SGE_PSTAT_TX_CSUM]++;
+       if (skb_shinfo(skb)->gso_size)
+               qs->port_stats[SGE_PSTAT_TSO]++;
+       if (vlan_tx_tag_present(skb) && pi->vlan_grp)
+               qs->port_stats[SGE_PSTAT_VLANINS]++;
+
+       dev->trans_start = jiffies;
+       spin_unlock(&q->lock);
+
+       /*
+        * We do not use Tx completion interrupts to free DMAd Tx packets.
+        * This is good for performamce but means that we rely on new Tx
+        * packets arriving to run the destructors of completed packets,
+        * which open up space in their sockets' send queues.  Sometimes
+        * we do not get such new packets causing Tx to stall.  A single
+        * UDP transmitter is a good example of this situation.  We have
+        * a clean up timer that periodically reclaims completed packets
+        * but it doesn't run often enough (nor do we want it to) to prevent
+        * lengthy stalls.  A solution to this problem is to run the
+        * destructor early, after the packet is queued but before it's DMAd.
+        * A cons is that we lie to socket memory accounting, but the amount
+        * of extra memory is reasonable (limited by the number of Tx
+        * descriptors), the packets do actually get freed quickly by new
+        * packets almost always, and for protocols like TCP that wait for
+        * acks to really free up the data the extra memory is even less.
+        * On the positive side we run the destructors on the sending CPU
+        * rather than on a potentially different completing CPU, usually a
+        * good thing.  We also run them without holding our Tx queue lock,
+        * unlike what reclaim_completed_tx() would otherwise do.
+        *
+        * Run the destructor before telling the DMA engine about the packet
+        * to make sure it doesn't complete and get freed prematurely.
+        */
+       if (likely(!skb_shared(skb)))
+               skb_orphan(skb);
+
+       write_tx_pkt_wr(adap, skb, pi, pidx, gen, q, ndesc, compl);
+       check_ring_tx_db(adap, q);
+       return NETDEV_TX_OK;
+}
+
+/**
+ *     write_imm - write a packet into a Tx descriptor as immediate data
+ *     @d: the Tx descriptor to write
+ *     @skb: the packet
+ *     @len: the length of packet data to write as immediate data
+ *     @gen: the generation bit value to write
+ *
+ *     Writes a packet as immediate data into a Tx descriptor.  The packet
+ *     contains a work request at its beginning.  We must write the packet
+ *     carefully so the SGE doesn't read accidentally before it's written in
+ *     its entirety.
+ */
+static inline void write_imm(struct tx_desc *d, struct sk_buff *skb,
+                            unsigned int len, unsigned int gen)
+{
+       struct work_request_hdr *from = (struct work_request_hdr *)skb->data;
+       struct work_request_hdr *to = (struct work_request_hdr *)d;
+
+       memcpy(&to[1], &from[1], len - sizeof(*from));
+       to->wr_hi = from->wr_hi | htonl(F_WR_SOP | F_WR_EOP |
+                                       V_WR_BCNTLFLT(len & 7));
+       wmb();
+       to->wr_lo = from->wr_lo | htonl(V_WR_GEN(gen) |
+                                       V_WR_LEN((len + 7) / 8));
+       wr_gen2(d, gen);
+       kfree_skb(skb);
+}
+
+/**
+ *     check_desc_avail - check descriptor availability on a send queue
+ *     @adap: the adapter
+ *     @q: the send queue
+ *     @skb: the packet needing the descriptors
+ *     @ndesc: the number of Tx descriptors needed
+ *     @qid: the Tx queue number in its queue set (TXQ_OFLD or TXQ_CTRL)
+ *
+ *     Checks if the requested number of Tx descriptors is available on an
+ *     SGE send queue.  If the queue is already suspended or not enough
+ *     descriptors are available the packet is queued for later transmission.
+ *     Must be called with the Tx queue locked.
+ *
+ *     Returns 0 if enough descriptors are available, 1 if there aren't
+ *     enough descriptors and the packet has been queued, and 2 if the caller
+ *     needs to retry because there weren't enough descriptors at the
+ *     beginning of the call but some freed up in the mean time.
+ */
+static inline int check_desc_avail(struct adapter *adap, struct sge_txq *q,
+                                  struct sk_buff *skb, unsigned int ndesc,
+                                  unsigned int qid)
+{
+       if (unlikely(!skb_queue_empty(&q->sendq))) {
+             addq_exit:__skb_queue_tail(&q->sendq, skb);
+               return 1;
+       }
+       if (unlikely(q->size - q->in_use < ndesc)) {
+               struct sge_qset *qs = txq_to_qset(q, qid);
+
+               set_bit(qid, &qs->txq_stopped);
+               smp_mb__after_clear_bit();
+
+               if (should_restart_tx(q) &&
+                   test_and_clear_bit(qid, &qs->txq_stopped))
+                       return 2;
+
+               q->stops++;
+               goto addq_exit;
+       }
+       return 0;
+}
+
+/**
+ *     reclaim_completed_tx_imm - reclaim completed control-queue Tx descs
+ *     @q: the SGE control Tx queue
+ *
+ *     This is a variant of reclaim_completed_tx() that is used for Tx queues
+ *     that send only immediate data (presently just the control queues) and
+ *     thus do not have any sk_buffs to release.
+ */
+static inline void reclaim_completed_tx_imm(struct sge_txq *q)
+{
+       unsigned int reclaim = q->processed - q->cleaned;
+
+       q->in_use -= reclaim;
+       q->cleaned += reclaim;
+}
+
+static inline int immediate(const struct sk_buff *skb)
+{
+       return skb->len <= WR_LEN && !skb->data_len;
+}
+
+/**
+ *     ctrl_xmit - send a packet through an SGE control Tx queue
+ *     @adap: the adapter
+ *     @q: the control queue
+ *     @skb: the packet
+ *
+ *     Send a packet through an SGE control Tx queue.  Packets sent through
+ *     a control queue must fit entirely as immediate data in a single Tx
+ *     descriptor and have no page fragments.
+ */
+static int ctrl_xmit(struct adapter *adap, struct sge_txq *q,
+                    struct sk_buff *skb)
+{
+       int ret;
+       struct work_request_hdr *wrp = (struct work_request_hdr *)skb->data;
+
+       if (unlikely(!immediate(skb))) {
+               WARN_ON(1);
+               dev_kfree_skb(skb);
+               return NET_XMIT_SUCCESS;
+       }
+
+       wrp->wr_hi |= htonl(F_WR_SOP | F_WR_EOP);
+       wrp->wr_lo = htonl(V_WR_TID(q->token));
+
+       spin_lock(&q->lock);
+      again:reclaim_completed_tx_imm(q);
+
+       ret = check_desc_avail(adap, q, skb, 1, TXQ_CTRL);
+       if (unlikely(ret)) {
+               if (ret == 1) {
+                       spin_unlock(&q->lock);
+                       return NET_XMIT_CN;
+               }
+               goto again;
+       }
+
+       write_imm(&q->desc[q->pidx], skb, skb->len, q->gen);
+
+       q->in_use++;
+       if (++q->pidx >= q->size) {
+               q->pidx = 0;
+               q->gen ^= 1;
+       }
+       spin_unlock(&q->lock);
+       wmb();
+       t3_write_reg(adap, A_SG_KDOORBELL,
+                    F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+       return NET_XMIT_SUCCESS;
+}
+
+/**
+ *     restart_ctrlq - restart a suspended control queue
+ *     @qs: the queue set cotaining the control queue
+ *
+ *     Resumes transmission on a suspended Tx control queue.
+ */
+static void restart_ctrlq(unsigned long data)
+{
+       struct sk_buff *skb;
+       struct sge_qset *qs = (struct sge_qset *)data;
+       struct sge_txq *q = &qs->txq[TXQ_CTRL];
+       struct adapter *adap = qs->netdev->priv;
+
+       spin_lock(&q->lock);
+      again:reclaim_completed_tx_imm(q);
+
+       while (q->in_use < q->size && (skb = __skb_dequeue(&q->sendq)) != NULL) {
+
+               write_imm(&q->desc[q->pidx], skb, skb->len, q->gen);
+
+               if (++q->pidx >= q->size) {
+                       q->pidx = 0;
+                       q->gen ^= 1;
+               }
+               q->in_use++;
+       }
+
+       if (!skb_queue_empty(&q->sendq)) {
+               set_bit(TXQ_CTRL, &qs->txq_stopped);
+               smp_mb__after_clear_bit();
+
+               if (should_restart_tx(q) &&
+                   test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped))
+                       goto again;
+               q->stops++;
+       }
+
+       spin_unlock(&q->lock);
+       t3_write_reg(adap, A_SG_KDOORBELL,
+                    F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+}
+
+/*
+ * Send a management message through control queue 0
+ */
+int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb)
+{
+       return ctrl_xmit(adap, &adap->sge.qs[0].txq[TXQ_CTRL], skb);
+}
+
+/**
+ *     write_ofld_wr - write an offload work request
+ *     @adap: the adapter
+ *     @skb: the packet to send
+ *     @q: the Tx queue
+ *     @pidx: index of the first Tx descriptor to write
+ *     @gen: the generation value to use
+ *     @ndesc: number of descriptors the packet will occupy
+ *
+ *     Write an offload work request to send the supplied packet.  The packet
+ *     data already carry the work request with most fields populated.
+ */
+static void write_ofld_wr(struct adapter *adap, struct sk_buff *skb,
+                         struct sge_txq *q, unsigned int pidx,
+                         unsigned int gen, unsigned int ndesc)
+{
+       unsigned int sgl_flits, flits;
+       struct work_request_hdr *from;
+       struct sg_ent *sgp, sgl[MAX_SKB_FRAGS / 2 + 1];
+       struct tx_desc *d = &q->desc[pidx];
+
+       if (immediate(skb)) {
+               q->sdesc[pidx].skb = NULL;
+               write_imm(d, skb, skb->len, gen);
+               return;
+       }
+
+       /* Only TX_DATA builds SGLs */
+
+       from = (struct work_request_hdr *)skb->data;
+       memcpy(&d->flit[1], &from[1], skb->h.raw - skb->data - sizeof(*from));
+
+       flits = (skb->h.raw - skb->data) / 8;
+       sgp = ndesc == 1 ? (struct sg_ent *)&d->flit[flits] : sgl;
+       sgl_flits = make_sgl(skb, sgp, skb->h.raw, skb->tail - skb->h.raw,
+                            adap->pdev);
+       if (need_skb_unmap())
+               ((struct unmap_info *)skb->cb)->len = skb->tail - skb->h.raw;
+
+       write_wr_hdr_sgl(ndesc, skb, d, pidx, q, sgl, flits, sgl_flits,
+                        gen, from->wr_hi, from->wr_lo);
+}
+
+/**
+ *     calc_tx_descs_ofld - calculate # of Tx descriptors for an offload packet
+ *     @skb: the packet
+ *
+ *     Returns the number of Tx descriptors needed for the given offload
+ *     packet.  These packets are already fully constructed.
+ */
+static inline unsigned int calc_tx_descs_ofld(const struct sk_buff *skb)
+{
+       unsigned int flits, cnt = skb_shinfo(skb)->nr_frags;
+
+       if (skb->len <= WR_LEN && cnt == 0)
+               return 1;       /* packet fits as immediate data */
+
+       flits = (skb->h.raw - skb->data) / 8;   /* headers */
+       if (skb->tail != skb->h.raw)
+               cnt++;
+       return flits_to_desc(flits + sgl_len(cnt));
+}
+
+/**
+ *     ofld_xmit - send a packet through an offload queue
+ *     @adap: the adapter
+ *     @q: the Tx offload queue
+ *     @skb: the packet
+ *
+ *     Send an offload packet through an SGE offload queue.
+ */
+static int ofld_xmit(struct adapter *adap, struct sge_txq *q,
+                    struct sk_buff *skb)
+{
+       int ret;
+       unsigned int ndesc = calc_tx_descs_ofld(skb), pidx, gen;
+
+       spin_lock(&q->lock);
+      again:reclaim_completed_tx(adap, q);
+
+       ret = check_desc_avail(adap, q, skb, ndesc, TXQ_OFLD);
+       if (unlikely(ret)) {
+               if (ret == 1) {
+                       skb->priority = ndesc;  /* save for restart */
+                       spin_unlock(&q->lock);
+                       return NET_XMIT_CN;
+               }
+               goto again;
+       }
+
+       gen = q->gen;
+       q->in_use += ndesc;
+       pidx = q->pidx;
+       q->pidx += ndesc;
+       if (q->pidx >= q->size) {
+               q->pidx -= q->size;
+               q->gen ^= 1;
+       }
+       spin_unlock(&q->lock);
+
+       write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
+       check_ring_tx_db(adap, q);
+       return NET_XMIT_SUCCESS;
+}
+
+/**
+ *     restart_offloadq - restart a suspended offload queue
+ *     @qs: the queue set cotaining the offload queue
+ *
+ *     Resumes transmission on a suspended Tx offload queue.
+ */
+static void restart_offloadq(unsigned long data)
+{
+       struct sk_buff *skb;
+       struct sge_qset *qs = (struct sge_qset *)data;
+       struct sge_txq *q = &qs->txq[TXQ_OFLD];
+       struct adapter *adap = qs->netdev->priv;
+
+       spin_lock(&q->lock);
+      again:reclaim_completed_tx(adap, q);
+
+       while ((skb = skb_peek(&q->sendq)) != NULL) {
+               unsigned int gen, pidx;
+               unsigned int ndesc = skb->priority;
+
+               if (unlikely(q->size - q->in_use < ndesc)) {
+                       set_bit(TXQ_OFLD, &qs->txq_stopped);
+                       smp_mb__after_clear_bit();
+
+                       if (should_restart_tx(q) &&
+                           test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped))
+                               goto again;
+                       q->stops++;
+                       break;
+               }
+
+               gen = q->gen;
+               q->in_use += ndesc;
+               pidx = q->pidx;
+               q->pidx += ndesc;
+               if (q->pidx >= q->size) {
+                       q->pidx -= q->size;
+                       q->gen ^= 1;
+               }
+               __skb_unlink(skb, &q->sendq);
+               spin_unlock(&q->lock);
+
+               write_ofld_wr(adap, skb, q, pidx, gen, ndesc);
+               spin_lock(&q->lock);
+       }
+       spin_unlock(&q->lock);
+
+#if USE_GTS
+       set_bit(TXQ_RUNNING, &q->flags);
+       set_bit(TXQ_LAST_PKT_DB, &q->flags);
+#endif
+       t3_write_reg(adap, A_SG_KDOORBELL,
+                    F_SELEGRCNTX | V_EGRCNTX(q->cntxt_id));
+}
+
+/**
+ *     queue_set - return the queue set a packet should use
+ *     @skb: the packet
+ *
+ *     Maps a packet to the SGE queue set it should use.  The desired queue
+ *     set is carried in bits 1-3 in the packet's priority.
+ */
+static inline int queue_set(const struct sk_buff *skb)
+{
+       return skb->priority >> 1;
+}
+
+/**
+ *     is_ctrl_pkt - return whether an offload packet is a control packet
+ *     @skb: the packet
+ *
+ *     Determines whether an offload packet should use an OFLD or a CTRL
+ *     Tx queue.  This is indicated by bit 0 in the packet's priority.
+ */
+static inline int is_ctrl_pkt(const struct sk_buff *skb)
+{
+       return skb->priority & 1;
+}
+
+/**
+ *     t3_offload_tx - send an offload packet
+ *     @tdev: the offload device to send to
+ *     @skb: the packet
+ *
+ *     Sends an offload packet.  We use the packet priority to select the
+ *     appropriate Tx queue as follows: bit 0 indicates whether the packet
+ *     should be sent as regular or control, bits 1-3 select the queue set.
+ */
+int t3_offload_tx(struct t3cdev *tdev, struct sk_buff *skb)
+{
+       struct adapter *adap = tdev2adap(tdev);
+       struct sge_qset *qs = &adap->sge.qs[queue_set(skb)];
+
+       if (unlikely(is_ctrl_pkt(skb)))
+               return ctrl_xmit(adap, &qs->txq[TXQ_CTRL], skb);
+
+       return ofld_xmit(adap, &qs->txq[TXQ_OFLD], skb);
+}
+
+/**
+ *     offload_enqueue - add an offload packet to an SGE offload receive queue
+ *     @q: the SGE response queue
+ *     @skb: the packet
+ *
+ *     Add a new offload packet to an SGE response queue's offload packet
+ *     queue.  If the packet is the first on the queue it schedules the RX
+ *     softirq to process the queue.
+ */
+static inline void offload_enqueue(struct sge_rspq *q, struct sk_buff *skb)
+{
+       skb->next = skb->prev = NULL;
+       if (q->rx_tail)
+               q->rx_tail->next = skb;
+       else {
+               struct sge_qset *qs = rspq_to_qset(q);
+
+               if (__netif_rx_schedule_prep(qs->netdev))
+                       __netif_rx_schedule(qs->netdev);
+               q->rx_head = skb;
+       }
+       q->rx_tail = skb;
+}
+
+/**
+ *     deliver_partial_bundle - deliver a (partial) bundle of Rx offload pkts
+ *     @tdev: the offload device that will be receiving the packets
+ *     @q: the SGE response queue that assembled the bundle
+ *     @skbs: the partial bundle
+ *     @n: the number of packets in the bundle
+ *
+ *     Delivers a (partial) bundle of Rx offload packets to an offload device.
+ */
+static inline void deliver_partial_bundle(struct t3cdev *tdev,
+                                         struct sge_rspq *q,
+                                         struct sk_buff *skbs[], int n)
+{
+       if (n) {
+               q->offload_bundles++;
+               tdev->recv(tdev, skbs, n);
+       }
+}
+
+/**
+ *     ofld_poll - NAPI handler for offload packets in interrupt mode
+ *     @dev: the network device doing the polling
+ *     @budget: polling budget
+ *
+ *     The NAPI handler for offload packets when a response queue is serviced
+ *     by the hard interrupt handler, i.e., when it's operating in non-polling
+ *     mode.  Creates small packet batches and sends them through the offload
+ *     receive handler.  Batches need to be of modest size as we do prefetches
+ *     on the packets in each.
+ */
+static int ofld_poll(struct net_device *dev, int *budget)
+{
+       struct adapter *adapter = dev->priv;
+       struct sge_qset *qs = dev2qset(dev);
+       struct sge_rspq *q = &qs->rspq;
+       int work_done, limit = min(*budget, dev->quota), avail = limit;
+
+       while (avail) {
+               struct sk_buff *head, *tail, *skbs[RX_BUNDLE_SIZE];
+               int ngathered;
+
+               spin_lock_irq(&q->lock);
+               head = q->rx_head;
+               if (!head) {
+                       work_done = limit - avail;
+                       *budget -= work_done;
+                       dev->quota -= work_done;
+                       __netif_rx_complete(dev);
+                       spin_unlock_irq(&q->lock);
+                       return 0;
+               }
+
+               tail = q->rx_tail;
+               q->rx_head = q->rx_tail = NULL;
+               spin_unlock_irq(&q->lock);
+
+               for (ngathered = 0; avail && head; avail--) {
+                       prefetch(head->data);
+                       skbs[ngathered] = head;
+                       head = head->next;
+                       skbs[ngathered]->next = NULL;
+                       if (++ngathered == RX_BUNDLE_SIZE) {
+                               q->offload_bundles++;
+                               adapter->tdev.recv(&adapter->tdev, skbs,
+                                                  ngathered);
+                               ngathered = 0;
+                       }
+               }
+               if (head) {     /* splice remaining packets back onto Rx queue */
+                       spin_lock_irq(&q->lock);
+                       tail->next = q->rx_head;
+                       if (!q->rx_head)
+                               q->rx_tail = tail;
+                       q->rx_head = head;
+                       spin_unlock_irq(&q->lock);
+               }
+               deliver_partial_bundle(&adapter->tdev, q, skbs, ngathered);
+       }
+       work_done = limit - avail;
+       *budget -= work_done;
+       dev->quota -= work_done;
+       return 1;
+}
+
+/**
+ *     rx_offload - process a received offload packet
+ *     @tdev: the offload device receiving the packet
+ *     @rq: the response queue that received the packet
+ *     @skb: the packet
+ *     @rx_gather: a gather list of packets if we are building a bundle
+ *     @gather_idx: index of the next available slot in the bundle
+ *
+ *     Process an ingress offload pakcet and add it to the offload ingress
+ *     queue.  Returns the index of the next available slot in the bundle.
+ */
+static inline int rx_offload(struct t3cdev *tdev, struct sge_rspq *rq,
+                            struct sk_buff *skb, struct sk_buff *rx_gather[],
+                            unsigned int gather_idx)
+{
+       rq->offload_pkts++;
+       skb->mac.raw = skb->nh.raw = skb->h.raw = skb->data;
+
+       if (rq->polling) {
+               rx_gather[gather_idx++] = skb;
+               if (gather_idx == RX_BUNDLE_SIZE) {
+                       tdev->recv(tdev, rx_gather, RX_BUNDLE_SIZE);
+                       gather_idx = 0;
+                       rq->offload_bundles++;
+               }
+       } else
+               offload_enqueue(rq, skb);
+
+       return gather_idx;
+}
+
+/**
+ *     restart_tx - check whether to restart suspended Tx queues
+ *     @qs: the queue set to resume
+ *
+ *     Restarts suspended Tx queues of an SGE queue set if they have enough
+ *     free resources to resume operation.
+ */
+static void restart_tx(struct sge_qset *qs)
+{
+       if (test_bit(TXQ_ETH, &qs->txq_stopped) &&
+           should_restart_tx(&qs->txq[TXQ_ETH]) &&
+           test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) {
+               qs->txq[TXQ_ETH].restarts++;
+               if (netif_running(qs->netdev))
+                       netif_wake_queue(qs->netdev);
+       }
+
+       if (test_bit(TXQ_OFLD, &qs->txq_stopped) &&
+           should_restart_tx(&qs->txq[TXQ_OFLD]) &&
+           test_and_clear_bit(TXQ_OFLD, &qs->txq_stopped)) {
+               qs->txq[TXQ_OFLD].restarts++;
+               tasklet_schedule(&qs->txq[TXQ_OFLD].qresume_tsk);
+       }
+       if (test_bit(TXQ_CTRL, &qs->txq_stopped) &&
+           should_restart_tx(&qs->txq[TXQ_CTRL]) &&
+           test_and_clear_bit(TXQ_CTRL, &qs->txq_stopped)) {
+               qs->txq[TXQ_CTRL].restarts++;
+               tasklet_schedule(&qs->txq[TXQ_CTRL].qresume_tsk);
+       }
+}
+
+/**
+ *     rx_eth - process an ingress ethernet packet
+ *     @adap: the adapter
+ *     @rq: the response queue that received the packet
+ *     @skb: the packet
+ *     @pad: amount of padding at the start of the buffer
+ *
+ *     Process an ingress ethernet pakcet and deliver it to the stack.
+ *     The padding is 2 if the packet was delivered in an Rx buffer and 0
+ *     if it was immediate data in a response.
+ */
+static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
+                  struct sk_buff *skb, int pad)
+{
+       struct cpl_rx_pkt *p = (struct cpl_rx_pkt *)(skb->data + pad);
+       struct port_info *pi;
+
+       rq->eth_pkts++;
+       skb_pull(skb, sizeof(*p) + pad);
+       skb->dev = adap->port[p->iff];
+       skb->dev->last_rx = jiffies;
+       skb->protocol = eth_type_trans(skb, skb->dev);
+       pi = netdev_priv(skb->dev);
+       if (pi->rx_csum_offload && p->csum_valid && p->csum == 0xffff &&
+           !p->fragment) {
+               rspq_to_qset(rq)->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++;
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+       } else
+               skb->ip_summed = CHECKSUM_NONE;
+
+       if (unlikely(p->vlan_valid)) {
+               struct vlan_group *grp = pi->vlan_grp;
+
+               rspq_to_qset(rq)->port_stats[SGE_PSTAT_VLANEX]++;
+               if (likely(grp))
+                       __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan),
+                                         rq->polling);
+               else
+                       dev_kfree_skb_any(skb);
+       } else if (rq->polling)
+               netif_receive_skb(skb);
+       else
+               netif_rx(skb);
+}
+
+/**
+ *     handle_rsp_cntrl_info - handles control information in a response
+ *     @qs: the queue set corresponding to the response
+ *     @flags: the response control flags
+ *
+ *     Handles the control information of an SGE response, such as GTS
+ *     indications and completion credits for the queue set's Tx queues.
+ *     HW coalesces credits, we don't do any extra SW coalescing.
+ */
+static inline void handle_rsp_cntrl_info(struct sge_qset *qs, u32 flags)
+{
+       unsigned int credits;
+
+#if USE_GTS
+       if (flags & F_RSPD_TXQ0_GTS)
+               clear_bit(TXQ_RUNNING, &qs->txq[TXQ_ETH].flags);
+#endif
+
+       credits = G_RSPD_TXQ0_CR(flags);
+       if (credits)
+               qs->txq[TXQ_ETH].processed += credits;
+
+       credits = G_RSPD_TXQ2_CR(flags);
+       if (credits)
+               qs->txq[TXQ_CTRL].processed += credits;
+
+# if USE_GTS
+       if (flags & F_RSPD_TXQ1_GTS)
+               clear_bit(TXQ_RUNNING, &qs->txq[TXQ_OFLD].flags);
+# endif
+       credits = G_RSPD_TXQ1_CR(flags);
+       if (credits)
+               qs->txq[TXQ_OFLD].processed += credits;
+}
+
+/**
+ *     check_ring_db - check if we need to ring any doorbells
+ *     @adapter: the adapter
+ *     @qs: the queue set whose Tx queues are to be examined
+ *     @sleeping: indicates which Tx queue sent GTS
+ *
+ *     Checks if some of a queue set's Tx queues need to ring their doorbells
+ *     to resume transmission after idling while they still have unprocessed
+ *     descriptors.
+ */
+static void check_ring_db(struct adapter *adap, struct sge_qset *qs,
+                         unsigned int sleeping)
+{
+       if (sleeping & F_RSPD_TXQ0_GTS) {
+               struct sge_txq *txq = &qs->txq[TXQ_ETH];
+
+               if (txq->cleaned + txq->in_use != txq->processed &&
+                   !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) {
+                       set_bit(TXQ_RUNNING, &txq->flags);
+                       t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX |
+                                    V_EGRCNTX(txq->cntxt_id));
+               }
+       }
+
+       if (sleeping & F_RSPD_TXQ1_GTS) {
+               struct sge_txq *txq = &qs->txq[TXQ_OFLD];
+
+               if (txq->cleaned + txq->in_use != txq->processed &&
+                   !test_and_set_bit(TXQ_LAST_PKT_DB, &txq->flags)) {
+                       set_bit(TXQ_RUNNING, &txq->flags);
+                       t3_write_reg(adap, A_SG_KDOORBELL, F_SELEGRCNTX |
+                                    V_EGRCNTX(txq->cntxt_id));
+               }
+       }
+}
+
+/**
+ *     is_new_response - check if a response is newly written
+ *     @r: the response descriptor
+ *     @q: the response queue
+ *
+ *     Returns true if a response descriptor contains a yet unprocessed
+ *     response.
+ */
+static inline int is_new_response(const struct rsp_desc *r,
+                                 const struct sge_rspq *q)
+{
+       return (r->intr_gen & F_RSPD_GEN2) == q->gen;
+}
+
+#define RSPD_GTS_MASK  (F_RSPD_TXQ0_GTS | F_RSPD_TXQ1_GTS)
+#define RSPD_CTRL_MASK (RSPD_GTS_MASK | \
+                       V_RSPD_TXQ0_CR(M_RSPD_TXQ0_CR) | \
+                       V_RSPD_TXQ1_CR(M_RSPD_TXQ1_CR) | \
+                       V_RSPD_TXQ2_CR(M_RSPD_TXQ2_CR))
+
+/* How long to delay the next interrupt in case of memory shortage, in 0.1us. */
+#define NOMEM_INTR_DELAY 2500
+
+/**
+ *     process_responses - process responses from an SGE response queue
+ *     @adap: the adapter
+ *     @qs: the queue set to which the response queue belongs
+ *     @budget: how many responses can be processed in this round
+ *
+ *     Process responses from an SGE response queue up to the supplied budget.
+ *     Responses include received packets as well as credits and other events
+ *     for the queues that belong to the response queue's queue set.
+ *     A negative budget is effectively unlimited.
+ *
+ *     Additionally choose the interrupt holdoff time for the next interrupt
+ *     on this queue.  If the system is under memory shortage use a fairly
+ *     long delay to help recovery.
+ */
+static int process_responses(struct adapter *adap, struct sge_qset *qs,
+                            int budget)
+{
+       struct sge_rspq *q = &qs->rspq;
+       struct rsp_desc *r = &q->desc[q->cidx];
+       int budget_left = budget;
+       unsigned int sleeping = 0;
+       struct sk_buff *offload_skbs[RX_BUNDLE_SIZE];
+       int ngathered = 0;
+
+       q->next_holdoff = q->holdoff_tmr;
+
+       while (likely(budget_left && is_new_response(r, q))) {
+               int eth, ethpad = 0;
+               struct sk_buff *skb = NULL;
+               u32 len, flags = ntohl(r->flags);
+               u32 rss_hi = *(const u32 *)r, rss_lo = r->rss_hdr.rss_hash_val;
+
+               eth = r->rss_hdr.opcode == CPL_RX_PKT;
+
+               if (unlikely(flags & F_RSPD_ASYNC_NOTIF)) {
+                       skb = alloc_skb(AN_PKT_SIZE, GFP_ATOMIC);
+                       if (!skb)
+                               goto no_mem;
+
+                       memcpy(__skb_put(skb, AN_PKT_SIZE), r, AN_PKT_SIZE);
+                       skb->data[0] = CPL_ASYNC_NOTIF;
+                       rss_hi = htonl(CPL_ASYNC_NOTIF << 24);
+                       q->async_notif++;
+               } else if (flags & F_RSPD_IMM_DATA_VALID) {
+                       skb = get_imm_packet(r);
+                       if (unlikely(!skb)) {
+                             no_mem:
+                               q->next_holdoff = NOMEM_INTR_DELAY;
+                               q->nomem++;
+                               /* consume one credit since we tried */
+                               budget_left--;
+                               break;
+                       }
+                       q->imm_data++;
+               } else if ((len = ntohl(r->len_cq)) != 0) {
+                       struct sge_fl *fl;
+
+                       fl = (len & F_RSPD_FLQ) ? &qs->fl[1] : &qs->fl[0];
+                       fl->credits--;
+                       skb = get_packet(adap, fl, G_RSPD_LEN(len),
+                                        eth ? SGE_RX_DROP_THRES : 0);
+                       if (!skb)
+                               q->rx_drops++;
+                       else if (r->rss_hdr.opcode == CPL_TRACE_PKT)
+                               __skb_pull(skb, 2);
+                       ethpad = 2;
+                       if (++fl->cidx == fl->size)
+                               fl->cidx = 0;
+               } else
+                       q->pure_rsps++;
+
+               if (flags & RSPD_CTRL_MASK) {
+                       sleeping |= flags & RSPD_GTS_MASK;
+                       handle_rsp_cntrl_info(qs, flags);
+               }
+
+               r++;
+               if (unlikely(++q->cidx == q->size)) {
+                       q->cidx = 0;
+                       q->gen ^= 1;
+                       r = q->desc;
+               }
+               prefetch(r);
+
+               if (++q->credits >= (q->size / 4)) {
+                       refill_rspq(adap, q, q->credits);
+                       q->credits = 0;
+               }
+
+               if (likely(skb != NULL)) {
+                       if (eth)
+                               rx_eth(adap, q, skb, ethpad);
+                       else {
+                               /* Preserve the RSS info in csum & priority */
+                               skb->csum = rss_hi;
+                               skb->priority = rss_lo;
+                               ngathered = rx_offload(&adap->tdev, q, skb,
+                                                      offload_skbs, ngathered);
+                       }
+               }
+
+               --budget_left;
+       }
+
+       deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered);
+       if (sleeping)
+               check_ring_db(adap, qs, sleeping);
+
+       smp_mb();               /* commit Tx queue .processed updates */
+       if (unlikely(qs->txq_stopped != 0))
+               restart_tx(qs);
+
+       budget -= budget_left;
+       return budget;
+}
+
+static inline int is_pure_response(const struct rsp_desc *r)
+{
+       u32 n = ntohl(r->flags) & (F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID);
+
+       return (n | r->len_cq) == 0;
+}
+
+/**
+ *     napi_rx_handler - the NAPI handler for Rx processing
+ *     @dev: the net device
+ *     @budget: how many packets we can process in this round
+ *
+ *     Handler for new data events when using NAPI.
+ */
+static int napi_rx_handler(struct net_device *dev, int *budget)
+{
+       struct adapter *adap = dev->priv;
+       struct sge_qset *qs = dev2qset(dev);
+       int effective_budget = min(*budget, dev->quota);
+
+       int work_done = process_responses(adap, qs, effective_budget);
+       *budget -= work_done;
+       dev->quota -= work_done;
+
+       if (work_done >= effective_budget)
+               return 1;
+
+       netif_rx_complete(dev);
+
+       /*
+        * Because we don't atomically flush the following write it is
+        * possible that in very rare cases it can reach the device in a way
+        * that races with a new response being written plus an error interrupt
+        * causing the NAPI interrupt handler below to return unhandled status
+        * to the OS.  To protect against this would require flushing the write
+        * and doing both the write and the flush with interrupts off.  Way too
+        * expensive and unjustifiable given the rarity of the race.
+        *
+        * The race cannot happen at all with MSI-X.
+        */
+       t3_write_reg(adap, A_SG_GTS, V_RSPQ(qs->rspq.cntxt_id) |
+                    V_NEWTIMER(qs->rspq.next_holdoff) |
+                    V_NEWINDEX(qs->rspq.cidx));
+       return 0;
+}
+
+/*
+ * Returns true if the device is already scheduled for polling.
+ */
+static inline int napi_is_scheduled(struct net_device *dev)
+{
+       return test_bit(__LINK_STATE_RX_SCHED, &dev->state);
+}
+
+/**
+ *     process_pure_responses - process pure responses from a response queue
+ *     @adap: the adapter
+ *     @qs: the queue set owning the response queue
+ *     @r: the first pure response to process
+ *
+ *     A simpler version of process_responses() that handles only pure (i.e.,
+ *     non data-carrying) responses.  Such respones are too light-weight to
+ *     justify calling a softirq under NAPI, so we handle them specially in
+ *     the interrupt handler.  The function is called with a pointer to a
+ *     response, which the caller must ensure is a valid pure response.
+ *
+ *     Returns 1 if it encounters a valid data-carrying response, 0 otherwise.
+ */
+static int process_pure_responses(struct adapter *adap, struct sge_qset *qs,
+                                 struct rsp_desc *r)
+{
+       struct sge_rspq *q = &qs->rspq;
+       unsigned int sleeping = 0;
+
+       do {
+               u32 flags = ntohl(r->flags);
+
+               r++;
+               if (unlikely(++q->cidx == q->size)) {
+                       q->cidx = 0;
+                       q->gen ^= 1;
+                       r = q->desc;
+               }
+               prefetch(r);
+
+               if (flags & RSPD_CTRL_MASK) {
+                       sleeping |= flags & RSPD_GTS_MASK;
+                       handle_rsp_cntrl_info(qs, flags);
+               }
+
+               q->pure_rsps++;
+               if (++q->credits >= (q->size / 4)) {
+                       refill_rspq(adap, q, q->credits);
+                       q->credits = 0;
+               }
+       } while (is_new_response(r, q) && is_pure_response(r));
+
+       if (sleeping)
+               check_ring_db(adap, qs, sleeping);
+
+       smp_mb();               /* commit Tx queue .processed updates */
+       if (unlikely(qs->txq_stopped != 0))
+               restart_tx(qs);
+
+       return is_new_response(r, q);
+}
+
+/**
+ *     handle_responses - decide what to do with new responses in NAPI mode
+ *     @adap: the adapter
+ *     @q: the response queue
+ *
+ *     This is used by the NAPI interrupt handlers to decide what to do with
+ *     new SGE responses.  If there are no new responses it returns -1.  If
+ *     there are new responses and they are pure (i.e., non-data carrying)
+ *     it handles them straight in hard interrupt context as they are very
+ *     cheap and don't deliver any packets.  Finally, if there are any data
+ *     signaling responses it schedules the NAPI handler.  Returns 1 if it
+ *     schedules NAPI, 0 if all new responses were pure.
+ *
+ *     The caller must ascertain NAPI is not already running.
+ */
+static inline int handle_responses(struct adapter *adap, struct sge_rspq *q)
+{
+       struct sge_qset *qs = rspq_to_qset(q);
+       struct rsp_desc *r = &q->desc[q->cidx];
+
+       if (!is_new_response(r, q))
+               return -1;
+       if (is_pure_response(r) && process_pure_responses(adap, qs, r) == 0) {
+               t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+                            V_NEWTIMER(q->holdoff_tmr) | V_NEWINDEX(q->cidx));
+               return 0;
+       }
+       if (likely(__netif_rx_schedule_prep(qs->netdev)))
+               __netif_rx_schedule(qs->netdev);
+       return 1;
+}
+
+/*
+ * The MSI-X interrupt handler for an SGE response queue for the non-NAPI case
+ * (i.e., response queue serviced in hard interrupt).
+ */
+irqreturn_t t3_sge_intr_msix(int irq, void *cookie)
+{
+       struct sge_qset *qs = cookie;
+       struct adapter *adap = qs->netdev->priv;
+       struct sge_rspq *q = &qs->rspq;
+
+       spin_lock(&q->lock);
+       if (process_responses(adap, qs, -1) == 0)
+               q->unhandled_irqs++;
+       t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+                    V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx));
+       spin_unlock(&q->lock);
+       return IRQ_HANDLED;
+}
+
+/*
+ * The MSI-X interrupt handler for an SGE response queue for the NAPI case
+ * (i.e., response queue serviced by NAPI polling).
+ */
+irqreturn_t t3_sge_intr_msix_napi(int irq, void *cookie)
+{
+       struct sge_qset *qs = cookie;
+       struct adapter *adap = qs->netdev->priv;
+       struct sge_rspq *q = &qs->rspq;
+
+       spin_lock(&q->lock);
+       BUG_ON(napi_is_scheduled(qs->netdev));
+
+       if (handle_responses(adap, q) < 0)
+               q->unhandled_irqs++;
+       spin_unlock(&q->lock);
+       return IRQ_HANDLED;
+}
+
+/*
+ * The non-NAPI MSI interrupt handler.  This needs to handle data events from
+ * SGE response queues as well as error and other async events as they all use
+ * the same MSI vector.  We use one SGE response queue per port in this mode
+ * and protect all response queues with queue 0's lock.
+ */
+static irqreturn_t t3_intr_msi(int irq, void *cookie)
+{
+       int new_packets = 0;
+       struct adapter *adap = cookie;
+       struct sge_rspq *q = &adap->sge.qs[0].rspq;
+
+       spin_lock(&q->lock);
+
+       if (process_responses(adap, &adap->sge.qs[0], -1)) {
+               t3_write_reg(adap, A_SG_GTS, V_RSPQ(q->cntxt_id) |
+                            V_NEWTIMER(q->next_holdoff) | V_NEWINDEX(q->cidx));
+               new_packets = 1;
+       }
+
+       if (adap->params.nports == 2 &&
+           process_responses(adap, &adap->sge.qs[1], -1)) {
+               struct sge_rspq *q1 = &adap->sge.qs[1].rspq;
+
+               t3_write_reg(adap, A_SG_GTS, V_RSPQ(q1->cntxt_id) |
+                            V_NEWTIMER(q1->next_holdoff) |
+                            V_NEWINDEX(q1->cidx));
+               new_packets = 1;
+       }
+
+       if (!new_packets && t3_slow_intr_handler(adap) == 0)
+               q->unhandled_irqs++;
+
+       spin_unlock(&q->lock);
+       return IRQ_HANDLED;
+}
+
+static int rspq_check_napi(struct net_device *dev, struct sge_rspq *q)
+{
+       if (!napi_is_scheduled(dev) && is_new_response(&q->desc[q->cidx], q)) {
+               if (likely(__netif_rx_schedule_prep(dev)))
+                       __netif_rx_schedule(dev);
+               return 1;
+       }
+       return 0;
+}
+
+/*
+ * The MSI interrupt handler for the NAPI case (i.e., response queues serviced
+ * by NAPI polling).  Handles data events from SGE response queues as well as
+ * error and other async events as they all use the same MSI vector.  We use
+ * one SGE response queue per port in this mode and protect all response
+ * queues with queue 0's lock.
+ */
+irqreturn_t t3_intr_msi_napi(int irq, void *cookie)
+{
+       int new_packets;
+       struct adapter *adap = cookie;
+       struct sge_rspq *q = &adap->sge.qs[0].rspq;
+
+       spin_lock(&q->lock);
+
+       new_packets = rspq_check_napi(adap->sge.qs[0].netdev, q);
+       if (adap->params.nports == 2)
+               new_packets += rspq_check_napi(adap->sge.qs[1].netdev,
+                                              &adap->sge.qs[1].rspq);
+       if (!new_packets && t3_slow_intr_handler(adap) == 0)
+               q->unhandled_irqs++;
+
+       spin_unlock(&q->lock);
+       return IRQ_HANDLED;
+}
+
+/*
+ * A helper function that processes responses and issues GTS.
+ */
+static inline int process_responses_gts(struct adapter *adap,
+                                       struct sge_rspq *rq)
+{
+       int work;
+
+       work = process_responses(adap, rspq_to_qset(rq), -1);
+       t3_write_reg(adap, A_SG_GTS, V_RSPQ(rq->cntxt_id) |
+                    V_NEWTIMER(rq->next_holdoff) | V_NEWINDEX(rq->cidx));
+       return work;
+}
+
+/*
+ * The legacy INTx interrupt handler.  This needs to handle data events from
+ * SGE response queues as well as error and other async events as they all use
+ * the same interrupt pin.  We use one SGE response queue per port in this mode
+ * and protect all response queues with queue 0's lock.
+ */
+static irqreturn_t t3_intr(int irq, void *cookie)
+{
+       int work_done, w0, w1;
+       struct adapter *adap = cookie;
+       struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+       struct sge_rspq *q1 = &adap->sge.qs[1].rspq;
+
+       spin_lock(&q0->lock);
+
+       w0 = is_new_response(&q0->desc[q0->cidx], q0);
+       w1 = adap->params.nports == 2 &&
+           is_new_response(&q1->desc[q1->cidx], q1);
+
+       if (likely(w0 | w1)) {
+               t3_write_reg(adap, A_PL_CLI, 0);
+               t3_read_reg(adap, A_PL_CLI);    /* flush */
+
+               if (likely(w0))
+                       process_responses_gts(adap, q0);
+
+               if (w1)
+                       process_responses_gts(adap, q1);
+
+               work_done = w0 | w1;
+       } else
+               work_done = t3_slow_intr_handler(adap);
+
+       spin_unlock(&q0->lock);
+       return IRQ_RETVAL(work_done != 0);
+}
+
+/*
+ * Interrupt handler for legacy INTx interrupts for T3B-based cards.
+ * Handles data events from SGE response queues as well as error and other
+ * async events as they all use the same interrupt pin.  We use one SGE
+ * response queue per port in this mode and protect all response queues with
+ * queue 0's lock.
+ */
+static irqreturn_t t3b_intr(int irq, void *cookie)
+{
+       u32 map;
+       struct adapter *adap = cookie;
+       struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+
+       t3_write_reg(adap, A_PL_CLI, 0);
+       map = t3_read_reg(adap, A_SG_DATA_INTR);
+
+       if (unlikely(!map))     /* shared interrupt, most likely */
+               return IRQ_NONE;
+
+       spin_lock(&q0->lock);
+
+       if (unlikely(map & F_ERRINTR))
+               t3_slow_intr_handler(adap);
+
+       if (likely(map & 1))
+               process_responses_gts(adap, q0);
+
+       if (map & 2)
+               process_responses_gts(adap, &adap->sge.qs[1].rspq);
+
+       spin_unlock(&q0->lock);
+       return IRQ_HANDLED;
+}
+
+/*
+ * NAPI interrupt handler for legacy INTx interrupts for T3B-based cards.
+ * Handles data events from SGE response queues as well as error and other
+ * async events as they all use the same interrupt pin.  We use one SGE
+ * response queue per port in this mode and protect all response queues with
+ * queue 0's lock.
+ */
+static irqreturn_t t3b_intr_napi(int irq, void *cookie)
+{
+       u32 map;
+       struct net_device *dev;
+       struct adapter *adap = cookie;
+       struct sge_rspq *q0 = &adap->sge.qs[0].rspq;
+
+       t3_write_reg(adap, A_PL_CLI, 0);
+       map = t3_read_reg(adap, A_SG_DATA_INTR);
+
+       if (unlikely(!map))     /* shared interrupt, most likely */
+               return IRQ_NONE;
+
+       spin_lock(&q0->lock);
+
+       if (unlikely(map & F_ERRINTR))
+               t3_slow_intr_handler(adap);
+
+       if (likely(map & 1)) {
+               dev = adap->sge.qs[0].netdev;
+
+               if (likely(__netif_rx_schedule_prep(dev)))
+                       __netif_rx_schedule(dev);
+       }
+       if (map & 2) {
+               dev = adap->sge.qs[1].netdev;
+
+               if (likely(__netif_rx_schedule_prep(dev)))
+                       __netif_rx_schedule(dev);
+       }
+
+       spin_unlock(&q0->lock);
+       return IRQ_HANDLED;
+}
+
+/**
+ *     t3_intr_handler - select the top-level interrupt handler
+ *     @adap: the adapter
+ *     @polling: whether using NAPI to service response queues
+ *
+ *     Selects the top-level interrupt handler based on the type of interrupts
+ *     (MSI-X, MSI, or legacy) and whether NAPI will be used to service the
+ *     response queues.
+ */
+intr_handler_t t3_intr_handler(struct adapter *adap, int polling)
+{
+       if (adap->flags & USING_MSIX)
+               return polling ? t3_sge_intr_msix_napi : t3_sge_intr_msix;
+       if (adap->flags & USING_MSI)
+               return polling ? t3_intr_msi_napi : t3_intr_msi;
+       if (adap->params.rev > 0)
+               return polling ? t3b_intr_napi : t3b_intr;
+       return t3_intr;
+}
+
+/**
+ *     t3_sge_err_intr_handler - SGE async event interrupt handler
+ *     @adapter: the adapter
+ *
+ *     Interrupt handler for SGE asynchronous (non-data) events.
+ */
+void t3_sge_err_intr_handler(struct adapter *adapter)
+{
+       unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE);
+
+       if (status & F_RSPQCREDITOVERFOW)
+               CH_ALERT(adapter, "SGE response queue credit overflow\n");
+
+       if (status & F_RSPQDISABLED) {
+               v = t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS);
+
+               CH_ALERT(adapter,
+                        "packet delivered to disabled response queue "
+                        "(0x%x)\n", (v >> S_RSPQ0DISABLED) & 0xff);
+       }
+
+       t3_write_reg(adapter, A_SG_INT_CAUSE, status);
+       if (status & (F_RSPQCREDITOVERFOW | F_RSPQDISABLED))
+               t3_fatal_err(adapter);
+}
+
+/**
+ *     sge_timer_cb - perform periodic maintenance of an SGE qset
+ *     @data: the SGE queue set to maintain
+ *
+ *     Runs periodically from a timer to perform maintenance of an SGE queue
+ *     set.  It performs two tasks:
+ *
+ *     a) Cleans up any completed Tx descriptors that may still be pending.
+ *     Normal descriptor cleanup happens when new packets are added to a Tx
+ *     queue so this timer is relatively infrequent and does any cleanup only
+ *     if the Tx queue has not seen any new packets in a while.  We make a
+ *     best effort attempt to reclaim descriptors, in that we don't wait
+ *     around if we cannot get a queue's lock (which most likely is because
+ *     someone else is queueing new packets and so will also handle the clean
+ *     up).  Since control queues use immediate data exclusively we don't
+ *     bother cleaning them up here.
+ *
+ *     b) Replenishes Rx queues that have run out due to memory shortage.
+ *     Normally new Rx buffers are added when existing ones are consumed but
+ *     when out of memory a queue can become empty.  We try to add only a few
+ *     buffers here, the queue will be replenished fully as these new buffers
+ *     are used up if memory shortage has subsided.
+ */
+static void sge_timer_cb(unsigned long data)
+{
+       spinlock_t *lock;
+       struct sge_qset *qs = (struct sge_qset *)data;
+       struct adapter *adap = qs->netdev->priv;
+
+       if (spin_trylock(&qs->txq[TXQ_ETH].lock)) {
+               reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]);
+               spin_unlock(&qs->txq[TXQ_ETH].lock);
+       }
+       if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) {
+               reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD]);
+               spin_unlock(&qs->txq[TXQ_OFLD].lock);
+       }
+       lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock :
+           &adap->sge.qs[0].rspq.lock;
+       if (spin_trylock_irq(lock)) {
+               if (!napi_is_scheduled(qs->netdev)) {
+                       if (qs->fl[0].credits < qs->fl[0].size)
+                               __refill_fl(adap, &qs->fl[0]);
+                       if (qs->fl[1].credits < qs->fl[1].size)
+                               __refill_fl(adap, &qs->fl[1]);
+               }
+               spin_unlock_irq(lock);
+       }
+       mod_timer(&qs->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+}
+
+/**
+ *     t3_update_qset_coalesce - update coalescing settings for a queue set
+ *     @qs: the SGE queue set
+ *     @p: new queue set parameters
+ *
+ *     Update the coalescing settings for an SGE queue set.  Nothing is done
+ *     if the queue set is not initialized yet.
+ */
+void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p)
+{
+       if (!qs->netdev)
+               return;
+
+       qs->rspq.holdoff_tmr = max(p->coalesce_usecs * 10, 1U);/* can't be 0 */
+       qs->rspq.polling = p->polling;
+       qs->netdev->poll = p->polling ? napi_rx_handler : ofld_poll;
+}
+
+/**
+ *     t3_sge_alloc_qset - initialize an SGE queue set
+ *     @adapter: the adapter
+ *     @id: the queue set id
+ *     @nports: how many Ethernet ports will be using this queue set
+ *     @irq_vec_idx: the IRQ vector index for response queue interrupts
+ *     @p: configuration parameters for this queue set
+ *     @ntxq: number of Tx queues for the queue set
+ *     @netdev: net device associated with this queue set
+ *
+ *     Allocate resources and initialize an SGE queue set.  A queue set
+ *     comprises a response queue, two Rx free-buffer queues, and up to 3
+ *     Tx queues.  The Tx queues are assigned roles in the order Ethernet
+ *     queue, offload queue, and control queue.
+ */
+int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
+                     int irq_vec_idx, const struct qset_params *p,
+                     int ntxq, struct net_device *netdev)
+{
+       int i, ret = -ENOMEM;
+       struct sge_qset *q = &adapter->sge.qs[id];
+
+       init_qset_cntxt(q, id);
+       init_timer(&q->tx_reclaim_timer);
+       q->tx_reclaim_timer.data = (unsigned long)q;
+       q->tx_reclaim_timer.function = sge_timer_cb;
+
+       q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size,
+                                  sizeof(struct rx_desc),
+                                  sizeof(struct rx_sw_desc),
+                                  &q->fl[0].phys_addr, &q->fl[0].sdesc);
+       if (!q->fl[0].desc)
+               goto err;
+
+       q->fl[1].desc = alloc_ring(adapter->pdev, p->jumbo_size,
+                                  sizeof(struct rx_desc),
+                                  sizeof(struct rx_sw_desc),
+                                  &q->fl[1].phys_addr, &q->fl[1].sdesc);
+       if (!q->fl[1].desc)
+               goto err;
+
+       q->rspq.desc = alloc_ring(adapter->pdev, p->rspq_size,
+                                 sizeof(struct rsp_desc), 0,
+                                 &q->rspq.phys_addr, NULL);
+       if (!q->rspq.desc)
+               goto err;
+
+       for (i = 0; i < ntxq; ++i) {
+               /*
+                * The control queue always uses immediate data so does not
+                * need to keep track of any sk_buffs.
+                */
+               size_t sz = i == TXQ_CTRL ? 0 : sizeof(struct tx_sw_desc);
+
+               q->txq[i].desc = alloc_ring(adapter->pdev, p->txq_size[i],
+                                           sizeof(struct tx_desc), sz,
+                                           &q->txq[i].phys_addr,
+                                           &q->txq[i].sdesc);
+               if (!q->txq[i].desc)
+                       goto err;
+
+               q->txq[i].gen = 1;
+               q->txq[i].size = p->txq_size[i];
+               spin_lock_init(&q->txq[i].lock);
+               skb_queue_head_init(&q->txq[i].sendq);
+       }
+
+       tasklet_init(&q->txq[TXQ_OFLD].qresume_tsk, restart_offloadq,
+                    (unsigned long)q);
+       tasklet_init(&q->txq[TXQ_CTRL].qresume_tsk, restart_ctrlq,
+                    (unsigned long)q);
+
+       q->fl[0].gen = q->fl[1].gen = 1;
+       q->fl[0].size = p->fl_size;
+       q->fl[1].size = p->jumbo_size;
+
+       q->rspq.gen = 1;
+       q->rspq.size = p->rspq_size;
+       spin_lock_init(&q->rspq.lock);
+
+       q->txq[TXQ_ETH].stop_thres = nports *
+           flits_to_desc(sgl_len(MAX_SKB_FRAGS + 1) + 3);
+
+       if (ntxq == 1) {
+               q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE + 2 +
+                   sizeof(struct cpl_rx_pkt);
+               q->fl[1].buf_size = MAX_FRAME_SIZE + 2 +
+                   sizeof(struct cpl_rx_pkt);
+       } else {
+               q->fl[0].buf_size = SGE_RX_SM_BUF_SIZE +
+                   sizeof(struct cpl_rx_data);
+               q->fl[1].buf_size = (16 * 1024) -
+                   SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+       }
+
+       spin_lock(&adapter->sge.reg_lock);
+
+       /* FL threshold comparison uses < */
+       ret = t3_sge_init_rspcntxt(adapter, q->rspq.cntxt_id, irq_vec_idx,
+                                  q->rspq.phys_addr, q->rspq.size,
+                                  q->fl[0].buf_size, 1, 0);
+       if (ret)
+               goto err_unlock;
+
+       for (i = 0; i < SGE_RXQ_PER_SET; ++i) {
+               ret = t3_sge_init_flcntxt(adapter, q->fl[i].cntxt_id, 0,
+                                         q->fl[i].phys_addr, q->fl[i].size,
+                                         q->fl[i].buf_size, p->cong_thres, 1,
+                                         0);
+               if (ret)
+                       goto err_unlock;
+       }
+
+       ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_ETH].cntxt_id, USE_GTS,
+                                SGE_CNTXT_ETH, id, q->txq[TXQ_ETH].phys_addr,
+                                q->txq[TXQ_ETH].size, q->txq[TXQ_ETH].token,
+                                1, 0);
+       if (ret)
+               goto err_unlock;
+
+       if (ntxq > 1) {
+               ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_OFLD].cntxt_id,
+                                        USE_GTS, SGE_CNTXT_OFLD, id,
+                                        q->txq[TXQ_OFLD].phys_addr,
+                                        q->txq[TXQ_OFLD].size, 0, 1, 0);
+               if (ret)
+                       goto err_unlock;
+       }
+
+       if (ntxq > 2) {
+               ret = t3_sge_init_ecntxt(adapter, q->txq[TXQ_CTRL].cntxt_id, 0,
+                                        SGE_CNTXT_CTRL, id,
+                                        q->txq[TXQ_CTRL].phys_addr,
+                                        q->txq[TXQ_CTRL].size,
+                                        q->txq[TXQ_CTRL].token, 1, 0);
+               if (ret)
+                       goto err_unlock;
+       }
+
+       spin_unlock(&adapter->sge.reg_lock);
+       q->netdev = netdev;
+       t3_update_qset_coalesce(q, p);
+
+       /*
+        * We use atalk_ptr as a backpointer to a qset.  In case a device is
+        * associated with multiple queue sets only the first one sets
+        * atalk_ptr.
+        */
+       if (netdev->atalk_ptr == NULL)
+               netdev->atalk_ptr = q;
+
+       refill_fl(adapter, &q->fl[0], q->fl[0].size, GFP_KERNEL);
+       refill_fl(adapter, &q->fl[1], q->fl[1].size, GFP_KERNEL);
+       refill_rspq(adapter, &q->rspq, q->rspq.size - 1);
+
+       t3_write_reg(adapter, A_SG_GTS, V_RSPQ(q->rspq.cntxt_id) |
+                    V_NEWTIMER(q->rspq.holdoff_tmr));
+
+       mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+       return 0;
+
+      err_unlock:
+       spin_unlock(&adapter->sge.reg_lock);
+      err:
+       t3_free_qset(adapter, q);
+       return ret;
+}
+
+/**
+ *     t3_free_sge_resources - free SGE resources
+ *     @adap: the adapter
+ *
+ *     Frees resources used by the SGE queue sets.
+ */
+void t3_free_sge_resources(struct adapter *adap)
+{
+       int i;
+
+       for (i = 0; i < SGE_QSETS; ++i)
+               t3_free_qset(adap, &adap->sge.qs[i]);
+}
+
+/**
+ *     t3_sge_start - enable SGE
+ *     @adap: the adapter
+ *
+ *     Enables the SGE for DMAs.  This is the last step in starting packet
+ *     transfers.
+ */
+void t3_sge_start(struct adapter *adap)
+{
+       t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, F_GLOBALENABLE);
+}
+
+/**
+ *     t3_sge_stop - disable SGE operation
+ *     @adap: the adapter
+ *
+ *     Disables the DMA engine.  This can be called in emeregencies (e.g.,
+ *     from error interrupts) or from normal process context.  In the latter
+ *     case it also disables any pending queue restart tasklets.  Note that
+ *     if it is called in interrupt context it cannot disable the restart
+ *     tasklets as it cannot wait, however the tasklets will have no effect
+ *     since the doorbells are disabled and the driver will call this again
+ *     later from process context, at which time the tasklets will be stopped
+ *     if they are still running.
+ */
+void t3_sge_stop(struct adapter *adap)
+{
+       t3_set_reg_field(adap, A_SG_CONTROL, F_GLOBALENABLE, 0);
+       if (!in_interrupt()) {
+               int i;
+
+               for (i = 0; i < SGE_QSETS; ++i) {
+                       struct sge_qset *qs = &adap->sge.qs[i];
+
+                       tasklet_kill(&qs->txq[TXQ_OFLD].qresume_tsk);
+                       tasklet_kill(&qs->txq[TXQ_CTRL].qresume_tsk);
+               }
+       }
+}
+
+/**
+ *     t3_sge_init - initialize SGE
+ *     @adap: the adapter
+ *     @p: the SGE parameters
+ *
+ *     Performs SGE initialization needed every time after a chip reset.
+ *     We do not initialize any of the queue sets here, instead the driver
+ *     top-level must request those individually.  We also do not enable DMA
+ *     here, that should be done after the queues have been set up.
+ */
+void t3_sge_init(struct adapter *adap, struct sge_params *p)
+{
+       unsigned int ctrl, ups = ffs(pci_resource_len(adap->pdev, 2) >> 12);
+
+       ctrl = F_DROPPKT | V_PKTSHIFT(2) | F_FLMODE | F_AVOIDCQOVFL |
+           F_CQCRDTCTRL |
+           V_HOSTPAGESIZE(PAGE_SHIFT - 11) | F_BIGENDIANINGRESS |
+           V_USERSPACESIZE(ups ? ups - 1 : 0) | F_ISCSICOALESCING;
+#if SGE_NUM_GENBITS == 1
+       ctrl |= F_EGRGENCTRL;
+#endif
+       if (adap->params.rev > 0) {
+               if (!(adap->flags & (USING_MSIX | USING_MSI)))
+                       ctrl |= F_ONEINTMULTQ | F_OPTONEINTMULTQ;
+               ctrl |= F_CQCRDTCTRL | F_AVOIDCQOVFL;
+       }
+       t3_write_reg(adap, A_SG_CONTROL, ctrl);
+       t3_write_reg(adap, A_SG_EGR_RCQ_DRB_THRSH, V_HIRCQDRBTHRSH(512) |
+                    V_LORCQDRBTHRSH(512));
+       t3_write_reg(adap, A_SG_TIMER_TICK, core_ticks_per_usec(adap) / 10);
+       t3_write_reg(adap, A_SG_CMDQ_CREDIT_TH, V_THRESHOLD(32) |
+                    V_TIMEOUT(200 * core_ticks_per_usec(adap)));
+       t3_write_reg(adap, A_SG_HI_DRB_HI_THRSH, 1000);
+       t3_write_reg(adap, A_SG_HI_DRB_LO_THRSH, 256);
+       t3_write_reg(adap, A_SG_LO_DRB_HI_THRSH, 1000);
+       t3_write_reg(adap, A_SG_LO_DRB_LO_THRSH, 256);
+       t3_write_reg(adap, A_SG_OCO_BASE, V_BASE1(0xfff));
+       t3_write_reg(adap, A_SG_DRB_PRI_THRESH, 63 * 1024);
+}
+
+/**
+ *     t3_sge_prep - one-time SGE initialization
+ *     @adap: the associated adapter
+ *     @p: SGE parameters
+ *
+ *     Performs one-time initialization of SGE SW state.  Includes determining
+ *     defaults for the assorted SGE parameters, which admins can change until
+ *     they are used to initialize the SGE.
+ */
+void __devinit t3_sge_prep(struct adapter *adap, struct sge_params *p)
+{
+       int i;
+
+       p->max_pkt_size = (16 * 1024) - sizeof(struct cpl_rx_data) -
+           SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+       for (i = 0; i < SGE_QSETS; ++i) {
+               struct qset_params *q = p->qset + i;
+
+               q->polling = adap->params.rev > 0;
+               q->coalesce_usecs = 5;
+               q->rspq_size = 1024;
+               q->fl_size = 4096;
+               q->jumbo_size = 512;
+               q->txq_size[TXQ_ETH] = 1024;
+               q->txq_size[TXQ_OFLD] = 1024;
+               q->txq_size[TXQ_CTRL] = 256;
+               q->cong_thres = 0;
+       }
+
+       spin_lock_init(&adap->sge.reg_lock);
+}
+
+/**
+ *     t3_get_desc - dump an SGE descriptor for debugging purposes
+ *     @qs: the queue set
+ *     @qnum: identifies the specific queue (0..2: Tx, 3:response, 4..5: Rx)
+ *     @idx: the descriptor index in the queue
+ *     @data: where to dump the descriptor contents
+ *
+ *     Dumps the contents of a HW descriptor of an SGE queue.  Returns the
+ *     size of the descriptor.
+ */
+int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx,
+               unsigned char *data)
+{
+       if (qnum >= 6)
+               return -EINVAL;
+
+       if (qnum < 3) {
+               if (!qs->txq[qnum].desc || idx >= qs->txq[qnum].size)
+                       return -EINVAL;
+               memcpy(data, &qs->txq[qnum].desc[idx], sizeof(struct tx_desc));
+               return sizeof(struct tx_desc);
+       }
+
+       if (qnum == 3) {
+               if (!qs->rspq.desc || idx >= qs->rspq.size)
+                       return -EINVAL;
+               memcpy(data, &qs->rspq.desc[idx], sizeof(struct rsp_desc));
+               return sizeof(struct rsp_desc);
+       }
+
+       qnum -= 4;
+       if (!qs->fl[qnum].desc || idx >= qs->fl[qnum].size)
+               return -EINVAL;
+       memcpy(data, &qs->fl[qnum].desc[idx], sizeof(struct rx_desc));
+       return sizeof(struct rx_desc);
+}
diff --git a/drivers/net/cxgb3/sge_defs.h b/drivers/net/cxgb3/sge_defs.h
new file mode 100644 (file)
index 0000000..514869e
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * This file is automatically generated --- any changes will be lost.
+ */
+
+#ifndef _SGE_DEFS_H
+#define _SGE_DEFS_H
+
+#define S_EC_CREDITS    0
+#define M_EC_CREDITS    0x7FFF
+#define V_EC_CREDITS(x) ((x) << S_EC_CREDITS)
+#define G_EC_CREDITS(x) (((x) >> S_EC_CREDITS) & M_EC_CREDITS)
+
+#define S_EC_GTS    15
+#define V_EC_GTS(x) ((x) << S_EC_GTS)
+#define F_EC_GTS    V_EC_GTS(1U)
+
+#define S_EC_INDEX    16
+#define M_EC_INDEX    0xFFFF
+#define V_EC_INDEX(x) ((x) << S_EC_INDEX)
+#define G_EC_INDEX(x) (((x) >> S_EC_INDEX) & M_EC_INDEX)
+
+#define S_EC_SIZE    0
+#define M_EC_SIZE    0xFFFF
+#define V_EC_SIZE(x) ((x) << S_EC_SIZE)
+#define G_EC_SIZE(x) (((x) >> S_EC_SIZE) & M_EC_SIZE)
+
+#define S_EC_BASE_LO    16
+#define M_EC_BASE_LO    0xFFFF
+#define V_EC_BASE_LO(x) ((x) << S_EC_BASE_LO)
+#define G_EC_BASE_LO(x) (((x) >> S_EC_BASE_LO) & M_EC_BASE_LO)
+
+#define S_EC_BASE_HI    0
+#define M_EC_BASE_HI    0xF
+#define V_EC_BASE_HI(x) ((x) << S_EC_BASE_HI)
+#define G_EC_BASE_HI(x) (((x) >> S_EC_BASE_HI) & M_EC_BASE_HI)
+
+#define S_EC_RESPQ    4
+#define M_EC_RESPQ    0x7
+#define V_EC_RESPQ(x) ((x) << S_EC_RESPQ)
+#define G_EC_RESPQ(x) (((x) >> S_EC_RESPQ) & M_EC_RESPQ)
+
+#define S_EC_TYPE    7
+#define M_EC_TYPE    0x7
+#define V_EC_TYPE(x) ((x) << S_EC_TYPE)
+#define G_EC_TYPE(x) (((x) >> S_EC_TYPE) & M_EC_TYPE)
+
+#define S_EC_GEN    10
+#define V_EC_GEN(x) ((x) << S_EC_GEN)
+#define F_EC_GEN    V_EC_GEN(1U)
+
+#define S_EC_UP_TOKEN    11
+#define M_EC_UP_TOKEN    0xFFFFF
+#define V_EC_UP_TOKEN(x) ((x) << S_EC_UP_TOKEN)
+#define G_EC_UP_TOKEN(x) (((x) >> S_EC_UP_TOKEN) & M_EC_UP_TOKEN)
+
+#define S_EC_VALID    31
+#define V_EC_VALID(x) ((x) << S_EC_VALID)
+#define F_EC_VALID    V_EC_VALID(1U)
+
+#define S_RQ_MSI_VEC    20
+#define M_RQ_MSI_VEC    0x3F
+#define V_RQ_MSI_VEC(x) ((x) << S_RQ_MSI_VEC)
+#define G_RQ_MSI_VEC(x) (((x) >> S_RQ_MSI_VEC) & M_RQ_MSI_VEC)
+
+#define S_RQ_INTR_EN    26
+#define V_RQ_INTR_EN(x) ((x) << S_RQ_INTR_EN)
+#define F_RQ_INTR_EN    V_RQ_INTR_EN(1U)
+
+#define S_RQ_GEN    28
+#define V_RQ_GEN(x) ((x) << S_RQ_GEN)
+#define F_RQ_GEN    V_RQ_GEN(1U)
+
+#define S_CQ_INDEX    0
+#define M_CQ_INDEX    0xFFFF
+#define V_CQ_INDEX(x) ((x) << S_CQ_INDEX)
+#define G_CQ_INDEX(x) (((x) >> S_CQ_INDEX) & M_CQ_INDEX)
+
+#define S_CQ_SIZE    16
+#define M_CQ_SIZE    0xFFFF
+#define V_CQ_SIZE(x) ((x) << S_CQ_SIZE)
+#define G_CQ_SIZE(x) (((x) >> S_CQ_SIZE) & M_CQ_SIZE)
+
+#define S_CQ_BASE_HI    0
+#define M_CQ_BASE_HI    0xFFFFF
+#define V_CQ_BASE_HI(x) ((x) << S_CQ_BASE_HI)
+#define G_CQ_BASE_HI(x) (((x) >> S_CQ_BASE_HI) & M_CQ_BASE_HI)
+
+#define S_CQ_RSPQ    20
+#define M_CQ_RSPQ    0x3F
+#define V_CQ_RSPQ(x) ((x) << S_CQ_RSPQ)
+#define G_CQ_RSPQ(x) (((x) >> S_CQ_RSPQ) & M_CQ_RSPQ)
+
+#define S_CQ_ASYNC_NOTIF    26
+#define V_CQ_ASYNC_NOTIF(x) ((x) << S_CQ_ASYNC_NOTIF)
+#define F_CQ_ASYNC_NOTIF    V_CQ_ASYNC_NOTIF(1U)
+
+#define S_CQ_ARMED    27
+#define V_CQ_ARMED(x) ((x) << S_CQ_ARMED)
+#define F_CQ_ARMED    V_CQ_ARMED(1U)
+
+#define S_CQ_ASYNC_NOTIF_SOL    28
+#define V_CQ_ASYNC_NOTIF_SOL(x) ((x) << S_CQ_ASYNC_NOTIF_SOL)
+#define F_CQ_ASYNC_NOTIF_SOL    V_CQ_ASYNC_NOTIF_SOL(1U)
+
+#define S_CQ_GEN    29
+#define V_CQ_GEN(x) ((x) << S_CQ_GEN)
+#define F_CQ_GEN    V_CQ_GEN(1U)
+
+#define S_CQ_OVERFLOW_MODE    31
+#define V_CQ_OVERFLOW_MODE(x) ((x) << S_CQ_OVERFLOW_MODE)
+#define F_CQ_OVERFLOW_MODE    V_CQ_OVERFLOW_MODE(1U)
+
+#define S_CQ_CREDITS    0
+#define M_CQ_CREDITS    0xFFFF
+#define V_CQ_CREDITS(x) ((x) << S_CQ_CREDITS)
+#define G_CQ_CREDITS(x) (((x) >> S_CQ_CREDITS) & M_CQ_CREDITS)
+
+#define S_CQ_CREDIT_THRES    16
+#define M_CQ_CREDIT_THRES    0x1FFF
+#define V_CQ_CREDIT_THRES(x) ((x) << S_CQ_CREDIT_THRES)
+#define G_CQ_CREDIT_THRES(x) (((x) >> S_CQ_CREDIT_THRES) & M_CQ_CREDIT_THRES)
+
+#define S_FL_BASE_HI    0
+#define M_FL_BASE_HI    0xFFFFF
+#define V_FL_BASE_HI(x) ((x) << S_FL_BASE_HI)
+#define G_FL_BASE_HI(x) (((x) >> S_FL_BASE_HI) & M_FL_BASE_HI)
+
+#define S_FL_INDEX_LO    20
+#define M_FL_INDEX_LO    0xFFF
+#define V_FL_INDEX_LO(x) ((x) << S_FL_INDEX_LO)
+#define G_FL_INDEX_LO(x) (((x) >> S_FL_INDEX_LO) & M_FL_INDEX_LO)
+
+#define S_FL_INDEX_HI    0
+#define M_FL_INDEX_HI    0xF
+#define V_FL_INDEX_HI(x) ((x) << S_FL_INDEX_HI)
+#define G_FL_INDEX_HI(x) (((x) >> S_FL_INDEX_HI) & M_FL_INDEX_HI)
+
+#define S_FL_SIZE    4
+#define M_FL_SIZE    0xFFFF
+#define V_FL_SIZE(x) ((x) << S_FL_SIZE)
+#define G_FL_SIZE(x) (((x) >> S_FL_SIZE) & M_FL_SIZE)
+
+#define S_FL_GEN    20
+#define V_FL_GEN(x) ((x) << S_FL_GEN)
+#define F_FL_GEN    V_FL_GEN(1U)
+
+#define S_FL_ENTRY_SIZE_LO    21
+#define M_FL_ENTRY_SIZE_LO    0x7FF
+#define V_FL_ENTRY_SIZE_LO(x) ((x) << S_FL_ENTRY_SIZE_LO)
+#define G_FL_ENTRY_SIZE_LO(x) (((x) >> S_FL_ENTRY_SIZE_LO) & M_FL_ENTRY_SIZE_LO)
+
+#define S_FL_ENTRY_SIZE_HI    0
+#define M_FL_ENTRY_SIZE_HI    0x1FFFFF
+#define V_FL_ENTRY_SIZE_HI(x) ((x) << S_FL_ENTRY_SIZE_HI)
+#define G_FL_ENTRY_SIZE_HI(x) (((x) >> S_FL_ENTRY_SIZE_HI) & M_FL_ENTRY_SIZE_HI)
+
+#define S_FL_CONG_THRES    21
+#define M_FL_CONG_THRES    0x3FF
+#define V_FL_CONG_THRES(x) ((x) << S_FL_CONG_THRES)
+#define G_FL_CONG_THRES(x) (((x) >> S_FL_CONG_THRES) & M_FL_CONG_THRES)
+
+#define S_FL_GTS    31
+#define V_FL_GTS(x) ((x) << S_FL_GTS)
+#define F_FL_GTS    V_FL_GTS(1U)
+
+#define S_FLD_GEN1    31
+#define V_FLD_GEN1(x) ((x) << S_FLD_GEN1)
+#define F_FLD_GEN1    V_FLD_GEN1(1U)
+
+#define S_FLD_GEN2    0
+#define V_FLD_GEN2(x) ((x) << S_FLD_GEN2)
+#define F_FLD_GEN2    V_FLD_GEN2(1U)
+
+#define S_RSPD_TXQ1_CR    0
+#define M_RSPD_TXQ1_CR    0x7F
+#define V_RSPD_TXQ1_CR(x) ((x) << S_RSPD_TXQ1_CR)
+#define G_RSPD_TXQ1_CR(x) (((x) >> S_RSPD_TXQ1_CR) & M_RSPD_TXQ1_CR)
+
+#define S_RSPD_TXQ1_GTS    7
+#define V_RSPD_TXQ1_GTS(x) ((x) << S_RSPD_TXQ1_GTS)
+#define F_RSPD_TXQ1_GTS    V_RSPD_TXQ1_GTS(1U)
+
+#define S_RSPD_TXQ2_CR    8
+#define M_RSPD_TXQ2_CR    0x7F
+#define V_RSPD_TXQ2_CR(x) ((x) << S_RSPD_TXQ2_CR)
+#define G_RSPD_TXQ2_CR(x) (((x) >> S_RSPD_TXQ2_CR) & M_RSPD_TXQ2_CR)
+
+#define S_RSPD_TXQ2_GTS    15
+#define V_RSPD_TXQ2_GTS(x) ((x) << S_RSPD_TXQ2_GTS)
+#define F_RSPD_TXQ2_GTS    V_RSPD_TXQ2_GTS(1U)
+
+#define S_RSPD_TXQ0_CR    16
+#define M_RSPD_TXQ0_CR    0x7F
+#define V_RSPD_TXQ0_CR(x) ((x) << S_RSPD_TXQ0_CR)
+#define G_RSPD_TXQ0_CR(x) (((x) >> S_RSPD_TXQ0_CR) & M_RSPD_TXQ0_CR)
+
+#define S_RSPD_TXQ0_GTS    23
+#define V_RSPD_TXQ0_GTS(x) ((x) << S_RSPD_TXQ0_GTS)
+#define F_RSPD_TXQ0_GTS    V_RSPD_TXQ0_GTS(1U)
+
+#define S_RSPD_EOP    24
+#define V_RSPD_EOP(x) ((x) << S_RSPD_EOP)
+#define F_RSPD_EOP    V_RSPD_EOP(1U)
+
+#define S_RSPD_SOP    25
+#define V_RSPD_SOP(x) ((x) << S_RSPD_SOP)
+#define F_RSPD_SOP    V_RSPD_SOP(1U)
+
+#define S_RSPD_ASYNC_NOTIF    26
+#define V_RSPD_ASYNC_NOTIF(x) ((x) << S_RSPD_ASYNC_NOTIF)
+#define F_RSPD_ASYNC_NOTIF    V_RSPD_ASYNC_NOTIF(1U)
+
+#define S_RSPD_FL0_GTS    27
+#define V_RSPD_FL0_GTS(x) ((x) << S_RSPD_FL0_GTS)
+#define F_RSPD_FL0_GTS    V_RSPD_FL0_GTS(1U)
+
+#define S_RSPD_FL1_GTS    28
+#define V_RSPD_FL1_GTS(x) ((x) << S_RSPD_FL1_GTS)
+#define F_RSPD_FL1_GTS    V_RSPD_FL1_GTS(1U)
+
+#define S_RSPD_IMM_DATA_VALID    29
+#define V_RSPD_IMM_DATA_VALID(x) ((x) << S_RSPD_IMM_DATA_VALID)
+#define F_RSPD_IMM_DATA_VALID    V_RSPD_IMM_DATA_VALID(1U)
+
+#define S_RSPD_OFFLOAD    30
+#define V_RSPD_OFFLOAD(x) ((x) << S_RSPD_OFFLOAD)
+#define F_RSPD_OFFLOAD    V_RSPD_OFFLOAD(1U)
+
+#define S_RSPD_GEN1    31
+#define V_RSPD_GEN1(x) ((x) << S_RSPD_GEN1)
+#define F_RSPD_GEN1    V_RSPD_GEN1(1U)
+
+#define S_RSPD_LEN    0
+#define M_RSPD_LEN    0x7FFFFFFF
+#define V_RSPD_LEN(x) ((x) << S_RSPD_LEN)
+#define G_RSPD_LEN(x) (((x) >> S_RSPD_LEN) & M_RSPD_LEN)
+
+#define S_RSPD_FLQ    31
+#define V_RSPD_FLQ(x) ((x) << S_RSPD_FLQ)
+#define F_RSPD_FLQ    V_RSPD_FLQ(1U)
+
+#define S_RSPD_GEN2    0
+#define V_RSPD_GEN2(x) ((x) << S_RSPD_GEN2)
+#define F_RSPD_GEN2    V_RSPD_GEN2(1U)
+
+#define S_RSPD_INR_VEC    1
+#define M_RSPD_INR_VEC    0x7F
+#define V_RSPD_INR_VEC(x) ((x) << S_RSPD_INR_VEC)
+#define G_RSPD_INR_VEC(x) (((x) >> S_RSPD_INR_VEC) & M_RSPD_INR_VEC)
+
+#endif                         /* _SGE_DEFS_H */
diff --git a/drivers/net/cxgb3/t3_cpl.h b/drivers/net/cxgb3/t3_cpl.h
new file mode 100644 (file)
index 0000000..b7a1a31
--- /dev/null
@@ -0,0 +1,1444 @@
+/*
+ * Copyright (c) 2004-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef T3_CPL_H
+#define T3_CPL_H
+
+#if !defined(__LITTLE_ENDIAN_BITFIELD) && !defined(__BIG_ENDIAN_BITFIELD)
+# include <asm/byteorder.h>
+#endif
+
+enum CPL_opcode {
+       CPL_PASS_OPEN_REQ = 0x1,
+       CPL_PASS_ACCEPT_RPL = 0x2,
+       CPL_ACT_OPEN_REQ = 0x3,
+       CPL_SET_TCB = 0x4,
+       CPL_SET_TCB_FIELD = 0x5,
+       CPL_GET_TCB = 0x6,
+       CPL_PCMD = 0x7,
+       CPL_CLOSE_CON_REQ = 0x8,
+       CPL_CLOSE_LISTSRV_REQ = 0x9,
+       CPL_ABORT_REQ = 0xA,
+       CPL_ABORT_RPL = 0xB,
+       CPL_TX_DATA = 0xC,
+       CPL_RX_DATA_ACK = 0xD,
+       CPL_TX_PKT = 0xE,
+       CPL_RTE_DELETE_REQ = 0xF,
+       CPL_RTE_WRITE_REQ = 0x10,
+       CPL_RTE_READ_REQ = 0x11,
+       CPL_L2T_WRITE_REQ = 0x12,
+       CPL_L2T_READ_REQ = 0x13,
+       CPL_SMT_WRITE_REQ = 0x14,
+       CPL_SMT_READ_REQ = 0x15,
+       CPL_TX_PKT_LSO = 0x16,
+       CPL_PCMD_READ = 0x17,
+       CPL_BARRIER = 0x18,
+       CPL_TID_RELEASE = 0x1A,
+
+       CPL_CLOSE_LISTSRV_RPL = 0x20,
+       CPL_ERROR = 0x21,
+       CPL_GET_TCB_RPL = 0x22,
+       CPL_L2T_WRITE_RPL = 0x23,
+       CPL_PCMD_READ_RPL = 0x24,
+       CPL_PCMD_RPL = 0x25,
+       CPL_PEER_CLOSE = 0x26,
+       CPL_RTE_DELETE_RPL = 0x27,
+       CPL_RTE_WRITE_RPL = 0x28,
+       CPL_RX_DDP_COMPLETE = 0x29,
+       CPL_RX_PHYS_ADDR = 0x2A,
+       CPL_RX_PKT = 0x2B,
+       CPL_RX_URG_NOTIFY = 0x2C,
+       CPL_SET_TCB_RPL = 0x2D,
+       CPL_SMT_WRITE_RPL = 0x2E,
+       CPL_TX_DATA_ACK = 0x2F,
+
+       CPL_ABORT_REQ_RSS = 0x30,
+       CPL_ABORT_RPL_RSS = 0x31,
+       CPL_CLOSE_CON_RPL = 0x32,
+       CPL_ISCSI_HDR = 0x33,
+       CPL_L2T_READ_RPL = 0x34,
+       CPL_RDMA_CQE = 0x35,
+       CPL_RDMA_CQE_READ_RSP = 0x36,
+       CPL_RDMA_CQE_ERR = 0x37,
+       CPL_RTE_READ_RPL = 0x38,
+       CPL_RX_DATA = 0x39,
+
+       CPL_ACT_OPEN_RPL = 0x40,
+       CPL_PASS_OPEN_RPL = 0x41,
+       CPL_RX_DATA_DDP = 0x42,
+       CPL_SMT_READ_RPL = 0x43,
+
+       CPL_ACT_ESTABLISH = 0x50,
+       CPL_PASS_ESTABLISH = 0x51,
+
+       CPL_PASS_ACCEPT_REQ = 0x70,
+
+       CPL_ASYNC_NOTIF = 0x80, /* fake opcode for async notifications */
+
+       CPL_TX_DMA_ACK = 0xA0,
+       CPL_RDMA_READ_REQ = 0xA1,
+       CPL_RDMA_TERMINATE = 0xA2,
+       CPL_TRACE_PKT = 0xA3,
+       CPL_RDMA_EC_STATUS = 0xA5,
+
+       NUM_CPL_CMDS            /* must be last and previous entries must be sorted */
+};
+
+enum CPL_error {
+       CPL_ERR_NONE = 0,
+       CPL_ERR_TCAM_PARITY = 1,
+       CPL_ERR_TCAM_FULL = 3,
+       CPL_ERR_CONN_RESET = 20,
+       CPL_ERR_CONN_EXIST = 22,
+       CPL_ERR_ARP_MISS = 23,
+       CPL_ERR_BAD_SYN = 24,
+       CPL_ERR_CONN_TIMEDOUT = 30,
+       CPL_ERR_XMIT_TIMEDOUT = 31,
+       CPL_ERR_PERSIST_TIMEDOUT = 32,
+       CPL_ERR_FINWAIT2_TIMEDOUT = 33,
+       CPL_ERR_KEEPALIVE_TIMEDOUT = 34,
+       CPL_ERR_RTX_NEG_ADVICE = 35,
+       CPL_ERR_PERSIST_NEG_ADVICE = 36,
+       CPL_ERR_ABORT_FAILED = 42,
+       CPL_ERR_GENERAL = 99
+};
+
+enum {
+       CPL_CONN_POLICY_AUTO = 0,
+       CPL_CONN_POLICY_ASK = 1,
+       CPL_CONN_POLICY_DENY = 3
+};
+
+enum {
+       ULP_MODE_NONE = 0,
+       ULP_MODE_ISCSI = 2,
+       ULP_MODE_RDMA = 4,
+       ULP_MODE_TCPDDP = 5
+};
+
+enum {
+       ULP_CRC_HEADER = 1 << 0,
+       ULP_CRC_DATA = 1 << 1
+};
+
+enum {
+       CPL_PASS_OPEN_ACCEPT,
+       CPL_PASS_OPEN_REJECT
+};
+
+enum {
+       CPL_ABORT_SEND_RST = 0,
+       CPL_ABORT_NO_RST,
+       CPL_ABORT_POST_CLOSE_REQ = 2
+};
+
+enum {                         /* TX_PKT_LSO ethernet types */
+       CPL_ETH_II,
+       CPL_ETH_II_VLAN,
+       CPL_ETH_802_3,
+       CPL_ETH_802_3_VLAN
+};
+
+enum {                         /* TCP congestion control algorithms */
+       CONG_ALG_RENO,
+       CONG_ALG_TAHOE,
+       CONG_ALG_NEWRENO,
+       CONG_ALG_HIGHSPEED
+};
+
+union opcode_tid {
+       __be32 opcode_tid;
+       __u8 opcode;
+};
+
+#define S_OPCODE 24
+#define V_OPCODE(x) ((x) << S_OPCODE)
+#define G_OPCODE(x) (((x) >> S_OPCODE) & 0xFF)
+#define G_TID(x)    ((x) & 0xFFFFFF)
+
+/* tid is assumed to be 24-bits */
+#define MK_OPCODE_TID(opcode, tid) (V_OPCODE(opcode) | (tid))
+
+#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid)
+
+/* extract the TID from a CPL command */
+#define GET_TID(cmd) (G_TID(ntohl(OPCODE_TID(cmd))))
+
+struct tcp_options {
+       __be16 mss;
+       __u8 wsf;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+        __u8:5;
+       __u8 ecn:1;
+       __u8 sack:1;
+       __u8 tstamp:1;
+#else
+       __u8 tstamp:1;
+       __u8 sack:1;
+       __u8 ecn:1;
+        __u8:5;
+#endif
+};
+
+struct rss_header {
+       __u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8 cpu_idx:6;
+       __u8 hash_type:2;
+#else
+       __u8 hash_type:2;
+       __u8 cpu_idx:6;
+#endif
+       __be16 cq_idx;
+       __be32 rss_hash_val;
+};
+
+#ifndef CHELSIO_FW
+struct work_request_hdr {
+       __be32 wr_hi;
+       __be32 wr_lo;
+};
+
+/* wr_hi fields */
+#define S_WR_SGE_CREDITS    0
+#define M_WR_SGE_CREDITS    0xFF
+#define V_WR_SGE_CREDITS(x) ((x) << S_WR_SGE_CREDITS)
+#define G_WR_SGE_CREDITS(x) (((x) >> S_WR_SGE_CREDITS) & M_WR_SGE_CREDITS)
+
+#define S_WR_SGLSFLT    8
+#define M_WR_SGLSFLT    0xFF
+#define V_WR_SGLSFLT(x) ((x) << S_WR_SGLSFLT)
+#define G_WR_SGLSFLT(x) (((x) >> S_WR_SGLSFLT) & M_WR_SGLSFLT)
+
+#define S_WR_BCNTLFLT    16
+#define M_WR_BCNTLFLT    0xF
+#define V_WR_BCNTLFLT(x) ((x) << S_WR_BCNTLFLT)
+#define G_WR_BCNTLFLT(x) (((x) >> S_WR_BCNTLFLT) & M_WR_BCNTLFLT)
+
+#define S_WR_DATATYPE    20
+#define V_WR_DATATYPE(x) ((x) << S_WR_DATATYPE)
+#define F_WR_DATATYPE    V_WR_DATATYPE(1U)
+
+#define S_WR_COMPL    21
+#define V_WR_COMPL(x) ((x) << S_WR_COMPL)
+#define F_WR_COMPL    V_WR_COMPL(1U)
+
+#define S_WR_EOP    22
+#define V_WR_EOP(x) ((x) << S_WR_EOP)
+#define F_WR_EOP    V_WR_EOP(1U)
+
+#define S_WR_SOP    23
+#define V_WR_SOP(x) ((x) << S_WR_SOP)
+#define F_WR_SOP    V_WR_SOP(1U)
+
+#define S_WR_OP    24
+#define M_WR_OP    0xFF
+#define V_WR_OP(x) ((x) << S_WR_OP)
+#define G_WR_OP(x) (((x) >> S_WR_OP) & M_WR_OP)
+
+/* wr_lo fields */
+#define S_WR_LEN    0
+#define M_WR_LEN    0xFF
+#define V_WR_LEN(x) ((x) << S_WR_LEN)
+#define G_WR_LEN(x) (((x) >> S_WR_LEN) & M_WR_LEN)
+
+#define S_WR_TID    8
+#define M_WR_TID    0xFFFFF
+#define V_WR_TID(x) ((x) << S_WR_TID)
+#define G_WR_TID(x) (((x) >> S_WR_TID) & M_WR_TID)
+
+#define S_WR_CR_FLUSH    30
+#define V_WR_CR_FLUSH(x) ((x) << S_WR_CR_FLUSH)
+#define F_WR_CR_FLUSH    V_WR_CR_FLUSH(1U)
+
+#define S_WR_GEN    31
+#define V_WR_GEN(x) ((x) << S_WR_GEN)
+#define F_WR_GEN    V_WR_GEN(1U)
+
+# define WR_HDR struct work_request_hdr wr
+# define RSS_HDR
+#else
+# define WR_HDR
+# define RSS_HDR struct rss_header rss_hdr;
+#endif
+
+/* option 0 lower-half fields */
+#define S_CPL_STATUS    0
+#define M_CPL_STATUS    0xFF
+#define V_CPL_STATUS(x) ((x) << S_CPL_STATUS)
+#define G_CPL_STATUS(x) (((x) >> S_CPL_STATUS) & M_CPL_STATUS)
+
+#define S_INJECT_TIMER    6
+#define V_INJECT_TIMER(x) ((x) << S_INJECT_TIMER)
+#define F_INJECT_TIMER    V_INJECT_TIMER(1U)
+
+#define S_NO_OFFLOAD    7
+#define V_NO_OFFLOAD(x) ((x) << S_NO_OFFLOAD)
+#define F_NO_OFFLOAD    V_NO_OFFLOAD(1U)
+
+#define S_ULP_MODE    8
+#define M_ULP_MODE    0xF
+#define V_ULP_MODE(x) ((x) << S_ULP_MODE)
+#define G_ULP_MODE(x) (((x) >> S_ULP_MODE) & M_ULP_MODE)
+
+#define S_RCV_BUFSIZ    12
+#define M_RCV_BUFSIZ    0x3FFF
+#define V_RCV_BUFSIZ(x) ((x) << S_RCV_BUFSIZ)
+#define G_RCV_BUFSIZ(x) (((x) >> S_RCV_BUFSIZ) & M_RCV_BUFSIZ)
+
+#define S_TOS    26
+#define M_TOS    0x3F
+#define V_TOS(x) ((x) << S_TOS)
+#define G_TOS(x) (((x) >> S_TOS) & M_TOS)
+
+/* option 0 upper-half fields */
+#define S_DELACK    0
+#define V_DELACK(x) ((x) << S_DELACK)
+#define F_DELACK    V_DELACK(1U)
+
+#define S_NO_CONG    1
+#define V_NO_CONG(x) ((x) << S_NO_CONG)
+#define F_NO_CONG    V_NO_CONG(1U)
+
+#define S_SRC_MAC_SEL    2
+#define M_SRC_MAC_SEL    0x3
+#define V_SRC_MAC_SEL(x) ((x) << S_SRC_MAC_SEL)
+#define G_SRC_MAC_SEL(x) (((x) >> S_SRC_MAC_SEL) & M_SRC_MAC_SEL)
+
+#define S_L2T_IDX    4
+#define M_L2T_IDX    0x7FF
+#define V_L2T_IDX(x) ((x) << S_L2T_IDX)
+#define G_L2T_IDX(x) (((x) >> S_L2T_IDX) & M_L2T_IDX)
+
+#define S_TX_CHANNEL    15
+#define V_TX_CHANNEL(x) ((x) << S_TX_CHANNEL)
+#define F_TX_CHANNEL    V_TX_CHANNEL(1U)
+
+#define S_TCAM_BYPASS    16
+#define V_TCAM_BYPASS(x) ((x) << S_TCAM_BYPASS)
+#define F_TCAM_BYPASS    V_TCAM_BYPASS(1U)
+
+#define S_NAGLE    17
+#define V_NAGLE(x) ((x) << S_NAGLE)
+#define F_NAGLE    V_NAGLE(1U)
+
+#define S_WND_SCALE    18
+#define M_WND_SCALE    0xF
+#define V_WND_SCALE(x) ((x) << S_WND_SCALE)
+#define G_WND_SCALE(x) (((x) >> S_WND_SCALE) & M_WND_SCALE)
+
+#define S_KEEP_ALIVE    22
+#define V_KEEP_ALIVE(x) ((x) << S_KEEP_ALIVE)
+#define F_KEEP_ALIVE    V_KEEP_ALIVE(1U)
+
+#define S_MAX_RETRANS    23
+#define M_MAX_RETRANS    0xF
+#define V_MAX_RETRANS(x) ((x) << S_MAX_RETRANS)
+#define G_MAX_RETRANS(x) (((x) >> S_MAX_RETRANS) & M_MAX_RETRANS)
+
+#define S_MAX_RETRANS_OVERRIDE    27
+#define V_MAX_RETRANS_OVERRIDE(x) ((x) << S_MAX_RETRANS_OVERRIDE)
+#define F_MAX_RETRANS_OVERRIDE    V_MAX_RETRANS_OVERRIDE(1U)
+
+#define S_MSS_IDX    28
+#define M_MSS_IDX    0xF
+#define V_MSS_IDX(x) ((x) << S_MSS_IDX)
+#define G_MSS_IDX(x) (((x) >> S_MSS_IDX) & M_MSS_IDX)
+
+/* option 1 fields */
+#define S_RSS_ENABLE    0
+#define V_RSS_ENABLE(x) ((x) << S_RSS_ENABLE)
+#define F_RSS_ENABLE    V_RSS_ENABLE(1U)
+
+#define S_RSS_MASK_LEN    1
+#define M_RSS_MASK_LEN    0x7
+#define V_RSS_MASK_LEN(x) ((x) << S_RSS_MASK_LEN)
+#define G_RSS_MASK_LEN(x) (((x) >> S_RSS_MASK_LEN) & M_RSS_MASK_LEN)
+
+#define S_CPU_IDX    4
+#define M_CPU_IDX    0x3F
+#define V_CPU_IDX(x) ((x) << S_CPU_IDX)
+#define G_CPU_IDX(x) (((x) >> S_CPU_IDX) & M_CPU_IDX)
+
+#define S_MAC_MATCH_VALID    18
+#define V_MAC_MATCH_VALID(x) ((x) << S_MAC_MATCH_VALID)
+#define F_MAC_MATCH_VALID    V_MAC_MATCH_VALID(1U)
+
+#define S_CONN_POLICY    19
+#define M_CONN_POLICY    0x3
+#define V_CONN_POLICY(x) ((x) << S_CONN_POLICY)
+#define G_CONN_POLICY(x) (((x) >> S_CONN_POLICY) & M_CONN_POLICY)
+
+#define S_SYN_DEFENSE    21
+#define V_SYN_DEFENSE(x) ((x) << S_SYN_DEFENSE)
+#define F_SYN_DEFENSE    V_SYN_DEFENSE(1U)
+
+#define S_VLAN_PRI    22
+#define M_VLAN_PRI    0x3
+#define V_VLAN_PRI(x) ((x) << S_VLAN_PRI)
+#define G_VLAN_PRI(x) (((x) >> S_VLAN_PRI) & M_VLAN_PRI)
+
+#define S_VLAN_PRI_VALID    24
+#define V_VLAN_PRI_VALID(x) ((x) << S_VLAN_PRI_VALID)
+#define F_VLAN_PRI_VALID    V_VLAN_PRI_VALID(1U)
+
+#define S_PKT_TYPE    25
+#define M_PKT_TYPE    0x3
+#define V_PKT_TYPE(x) ((x) << S_PKT_TYPE)
+#define G_PKT_TYPE(x) (((x) >> S_PKT_TYPE) & M_PKT_TYPE)
+
+#define S_MAC_MATCH    27
+#define M_MAC_MATCH    0x1F
+#define V_MAC_MATCH(x) ((x) << S_MAC_MATCH)
+#define G_MAC_MATCH(x) (((x) >> S_MAC_MATCH) & M_MAC_MATCH)
+
+/* option 2 fields */
+#define S_CPU_INDEX    0
+#define M_CPU_INDEX    0x7F
+#define V_CPU_INDEX(x) ((x) << S_CPU_INDEX)
+#define G_CPU_INDEX(x) (((x) >> S_CPU_INDEX) & M_CPU_INDEX)
+
+#define S_CPU_INDEX_VALID    7
+#define V_CPU_INDEX_VALID(x) ((x) << S_CPU_INDEX_VALID)
+#define F_CPU_INDEX_VALID    V_CPU_INDEX_VALID(1U)
+
+#define S_RX_COALESCE    8
+#define M_RX_COALESCE    0x3
+#define V_RX_COALESCE(x) ((x) << S_RX_COALESCE)
+#define G_RX_COALESCE(x) (((x) >> S_RX_COALESCE) & M_RX_COALESCE)
+
+#define S_RX_COALESCE_VALID    10
+#define V_RX_COALESCE_VALID(x) ((x) << S_RX_COALESCE_VALID)
+#define F_RX_COALESCE_VALID    V_RX_COALESCE_VALID(1U)
+
+#define S_CONG_CONTROL_FLAVOR    11
+#define M_CONG_CONTROL_FLAVOR    0x3
+#define V_CONG_CONTROL_FLAVOR(x) ((x) << S_CONG_CONTROL_FLAVOR)
+#define G_CONG_CONTROL_FLAVOR(x) (((x) >> S_CONG_CONTROL_FLAVOR) & M_CONG_CONTROL_FLAVOR)
+
+#define S_PACING_FLAVOR    13
+#define M_PACING_FLAVOR    0x3
+#define V_PACING_FLAVOR(x) ((x) << S_PACING_FLAVOR)
+#define G_PACING_FLAVOR(x) (((x) >> S_PACING_FLAVOR) & M_PACING_FLAVOR)
+
+#define S_FLAVORS_VALID    15
+#define V_FLAVORS_VALID(x) ((x) << S_FLAVORS_VALID)
+#define F_FLAVORS_VALID    V_FLAVORS_VALID(1U)
+
+#define S_RX_FC_DISABLE    16
+#define V_RX_FC_DISABLE(x) ((x) << S_RX_FC_DISABLE)
+#define F_RX_FC_DISABLE    V_RX_FC_DISABLE(1U)
+
+#define S_RX_FC_VALID    17
+#define V_RX_FC_VALID(x) ((x) << S_RX_FC_VALID)
+#define F_RX_FC_VALID    V_RX_FC_VALID(1U)
+
+struct cpl_pass_open_req {
+       WR_HDR;
+       union opcode_tid ot;
+       __be16 local_port;
+       __be16 peer_port;
+       __be32 local_ip;
+       __be32 peer_ip;
+       __be32 opt0h;
+       __be32 opt0l;
+       __be32 peer_netmask;
+       __be32 opt1;
+};
+
+struct cpl_pass_open_rpl {
+       RSS_HDR union opcode_tid ot;
+       __be16 local_port;
+       __be16 peer_port;
+       __be32 local_ip;
+       __be32 peer_ip;
+       __u8 resvd[7];
+       __u8 status;
+};
+
+struct cpl_pass_establish {
+       RSS_HDR union opcode_tid ot;
+       __be16 local_port;
+       __be16 peer_port;
+       __be32 local_ip;
+       __be32 peer_ip;
+       __be32 tos_tid;
+       __be16 l2t_idx;
+       __be16 tcp_opt;
+       __be32 snd_isn;
+       __be32 rcv_isn;
+};
+
+/* cpl_pass_establish.tos_tid fields */
+#define S_PASS_OPEN_TID    0
+#define M_PASS_OPEN_TID    0xFFFFFF
+#define V_PASS_OPEN_TID(x) ((x) << S_PASS_OPEN_TID)
+#define G_PASS_OPEN_TID(x) (((x) >> S_PASS_OPEN_TID) & M_PASS_OPEN_TID)
+
+#define S_PASS_OPEN_TOS    24
+#define M_PASS_OPEN_TOS    0xFF
+#define V_PASS_OPEN_TOS(x) ((x) << S_PASS_OPEN_TOS)
+#define G_PASS_OPEN_TOS(x) (((x) >> S_PASS_OPEN_TOS) & M_PASS_OPEN_TOS)
+
+/* cpl_pass_establish.l2t_idx fields */
+#define S_L2T_IDX16    5
+#define M_L2T_IDX16    0x7FF
+#define V_L2T_IDX16(x) ((x) << S_L2T_IDX16)
+#define G_L2T_IDX16(x) (((x) >> S_L2T_IDX16) & M_L2T_IDX16)
+
+/* cpl_pass_establish.tcp_opt fields (also applies act_open_establish) */
+#define G_TCPOPT_WSCALE_OK(x)  (((x) >> 5) & 1)
+#define G_TCPOPT_SACK(x)       (((x) >> 6) & 1)
+#define G_TCPOPT_TSTAMP(x)     (((x) >> 7) & 1)
+#define G_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf)
+#define G_TCPOPT_MSS(x)        (((x) >> 12) & 0xf)
+
+struct cpl_pass_accept_req {
+       RSS_HDR union opcode_tid ot;
+       __be16 local_port;
+       __be16 peer_port;
+       __be32 local_ip;
+       __be32 peer_ip;
+       __be32 tos_tid;
+       struct tcp_options tcp_options;
+       __u8 dst_mac[6];
+       __be16 vlan_tag;
+       __u8 src_mac[6];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+        __u8:3;
+       __u8 addr_idx:3;
+       __u8 port_idx:1;
+       __u8 exact_match:1;
+#else
+       __u8 exact_match:1;
+       __u8 port_idx:1;
+       __u8 addr_idx:3;
+        __u8:3;
+#endif
+       __u8 rsvd;
+       __be32 rcv_isn;
+       __be32 rsvd2;
+};
+
+struct cpl_pass_accept_rpl {
+       WR_HDR;
+       union opcode_tid ot;
+       __be32 opt2;
+       __be32 rsvd;
+       __be32 peer_ip;
+       __be32 opt0h;
+       __be32 opt0l_status;
+};
+
+struct cpl_act_open_req {
+       WR_HDR;
+       union opcode_tid ot;
+       __be16 local_port;
+       __be16 peer_port;
+       __be32 local_ip;
+       __be32 peer_ip;
+       __be32 opt0h;
+       __be32 opt0l;
+       __be32 params;
+       __be32 opt2;
+};
+
+/* cpl_act_open_req.params fields */
+#define S_AOPEN_VLAN_PRI    9
+#define M_AOPEN_VLAN_PRI    0x3
+#define V_AOPEN_VLAN_PRI(x) ((x) << S_AOPEN_VLAN_PRI)
+#define G_AOPEN_VLAN_PRI(x) (((x) >> S_AOPEN_VLAN_PRI) & M_AOPEN_VLAN_PRI)
+
+#define S_AOPEN_VLAN_PRI_VALID    11
+#define V_AOPEN_VLAN_PRI_VALID(x) ((x) << S_AOPEN_VLAN_PRI_VALID)
+#define F_AOPEN_VLAN_PRI_VALID    V_AOPEN_VLAN_PRI_VALID(1U)
+
+#define S_AOPEN_PKT_TYPE    12
+#define M_AOPEN_PKT_TYPE    0x3
+#define V_AOPEN_PKT_TYPE(x) ((x) << S_AOPEN_PKT_TYPE)
+#define G_AOPEN_PKT_TYPE(x) (((x) >> S_AOPEN_PKT_TYPE) & M_AOPEN_PKT_TYPE)
+
+#define S_AOPEN_MAC_MATCH    14
+#define M_AOPEN_MAC_MATCH    0x1F
+#define V_AOPEN_MAC_MATCH(x) ((x) << S_AOPEN_MAC_MATCH)
+#define G_AOPEN_MAC_MATCH(x) (((x) >> S_AOPEN_MAC_MATCH) & M_AOPEN_MAC_MATCH)
+
+#define S_AOPEN_MAC_MATCH_VALID    19
+#define V_AOPEN_MAC_MATCH_VALID(x) ((x) << S_AOPEN_MAC_MATCH_VALID)
+#define F_AOPEN_MAC_MATCH_VALID    V_AOPEN_MAC_MATCH_VALID(1U)
+
+#define S_AOPEN_IFF_VLAN    20
+#define M_AOPEN_IFF_VLAN    0xFFF
+#define V_AOPEN_IFF_VLAN(x) ((x) << S_AOPEN_IFF_VLAN)
+#define G_AOPEN_IFF_VLAN(x) (((x) >> S_AOPEN_IFF_VLAN) & M_AOPEN_IFF_VLAN)
+
+struct cpl_act_open_rpl {
+       RSS_HDR union opcode_tid ot;
+       __be16 local_port;
+       __be16 peer_port;
+       __be32 local_ip;
+       __be32 peer_ip;
+       __be32 atid;
+       __u8 rsvd[3];
+       __u8 status;
+};
+
+struct cpl_act_establish {
+       RSS_HDR union opcode_tid ot;
+       __be16 local_port;
+       __be16 peer_port;
+       __be32 local_ip;
+       __be32 peer_ip;
+       __be32 tos_tid;
+       __be16 l2t_idx;
+       __be16 tcp_opt;
+       __be32 snd_isn;
+       __be32 rcv_isn;
+};
+
+struct cpl_get_tcb {
+       WR_HDR;
+       union opcode_tid ot;
+       __be16 cpuno;
+       __be16 rsvd;
+};
+
+struct cpl_get_tcb_rpl {
+       RSS_HDR union opcode_tid ot;
+       __u8 rsvd;
+       __u8 status;
+       __be16 len;
+};
+
+struct cpl_set_tcb {
+       WR_HDR;
+       union opcode_tid ot;
+       __u8 reply;
+       __u8 cpu_idx;
+       __be16 len;
+};
+
+/* cpl_set_tcb.reply fields */
+#define S_NO_REPLY    7
+#define V_NO_REPLY(x) ((x) << S_NO_REPLY)
+#define F_NO_REPLY    V_NO_REPLY(1U)
+
+struct cpl_set_tcb_field {
+       WR_HDR;
+       union opcode_tid ot;
+       __u8 reply;
+       __u8 cpu_idx;
+       __be16 word;
+       __be64 mask;
+       __be64 val;
+};
+
+struct cpl_set_tcb_rpl {
+       RSS_HDR union opcode_tid ot;
+       __u8 rsvd[3];
+       __u8 status;
+};
+
+struct cpl_pcmd {
+       WR_HDR;
+       union opcode_tid ot;
+       __u8 rsvd[3];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8 src:1;
+       __u8 bundle:1;
+       __u8 channel:1;
+        __u8:5;
+#else
+        __u8:5;
+       __u8 channel:1;
+       __u8 bundle:1;
+       __u8 src:1;
+#endif
+       __be32 pcmd_parm[2];
+};
+
+struct cpl_pcmd_reply {
+       RSS_HDR union opcode_tid ot;
+       __u8 status;
+       __u8 rsvd;
+       __be16 len;
+};
+
+struct cpl_close_con_req {
+       WR_HDR;
+       union opcode_tid ot;
+       __be32 rsvd;
+};
+
+struct cpl_close_con_rpl {
+       RSS_HDR union opcode_tid ot;
+       __u8 rsvd[3];
+       __u8 status;
+       __be32 snd_nxt;
+       __be32 rcv_nxt;
+};
+
+struct cpl_close_listserv_req {
+       WR_HDR;
+       union opcode_tid ot;
+       __u8 rsvd0;
+       __u8 cpu_idx;
+       __be16 rsvd1;
+};
+
+struct cpl_close_listserv_rpl {
+       RSS_HDR union opcode_tid ot;
+       __u8 rsvd[3];
+       __u8 status;
+};
+
+struct cpl_abort_req_rss {
+       RSS_HDR union opcode_tid ot;
+       __be32 rsvd0;
+       __u8 rsvd1;
+       __u8 status;
+       __u8 rsvd2[6];
+};
+
+struct cpl_abort_req {
+       WR_HDR;
+       union opcode_tid ot;
+       __be32 rsvd0;
+       __u8 rsvd1;
+       __u8 cmd;
+       __u8 rsvd2[6];
+};
+
+struct cpl_abort_rpl_rss {
+       RSS_HDR union opcode_tid ot;
+       __be32 rsvd0;
+       __u8 rsvd1;
+       __u8 status;
+       __u8 rsvd2[6];
+};
+
+struct cpl_abort_rpl {
+       WR_HDR;
+       union opcode_tid ot;
+       __be32 rsvd0;
+       __u8 rsvd1;
+       __u8 cmd;
+       __u8 rsvd2[6];
+};
+
+struct cpl_peer_close {
+       RSS_HDR union opcode_tid ot;
+       __be32 rcv_nxt;
+};
+
+struct tx_data_wr {
+       __be32 wr_hi;
+       __be32 wr_lo;
+       __be32 len;
+       __be32 flags;
+       __be32 sndseq;
+       __be32 param;
+};
+
+/* tx_data_wr.param fields */
+#define S_TX_PORT    0
+#define M_TX_PORT    0x7
+#define V_TX_PORT(x) ((x) << S_TX_PORT)
+#define G_TX_PORT(x) (((x) >> S_TX_PORT) & M_TX_PORT)
+
+#define S_TX_MSS    4
+#define M_TX_MSS    0xF
+#define V_TX_MSS(x) ((x) << S_TX_MSS)
+#define G_TX_MSS(x) (((x) >> S_TX_MSS) & M_TX_MSS)
+
+#define S_TX_QOS    8
+#define M_TX_QOS    0xFF
+#define V_TX_QOS(x) ((x) << S_TX_QOS)
+#define G_TX_QOS(x) (((x) >> S_TX_QOS) & M_TX_QOS)
+
+#define S_TX_SNDBUF 16
+#define M_TX_SNDBUF 0xFFFF
+#define V_TX_SNDBUF(x) ((x) << S_TX_SNDBUF)
+#define G_TX_SNDBUF(x) (((x) >> S_TX_SNDBUF) & M_TX_SNDBUF)
+
+struct cpl_tx_data {
+       union opcode_tid ot;
+       __be32 len;
+       __be32 rsvd;
+       __be16 urg;
+       __be16 flags;
+};
+
+/* cpl_tx_data.flags fields */
+#define S_TX_ULP_SUBMODE    6
+#define M_TX_ULP_SUBMODE    0xF
+#define V_TX_ULP_SUBMODE(x) ((x) << S_TX_ULP_SUBMODE)
+#define G_TX_ULP_SUBMODE(x) (((x) >> S_TX_ULP_SUBMODE) & M_TX_ULP_SUBMODE)
+
+#define S_TX_ULP_MODE    10
+#define M_TX_ULP_MODE    0xF
+#define V_TX_ULP_MODE(x) ((x) << S_TX_ULP_MODE)
+#define G_TX_ULP_MODE(x) (((x) >> S_TX_ULP_MODE) & M_TX_ULP_MODE)
+
+#define S_TX_SHOVE    14
+#define V_TX_SHOVE(x) ((x) << S_TX_SHOVE)
+#define F_TX_SHOVE    V_TX_SHOVE(1U)
+
+#define S_TX_MORE    15
+#define V_TX_MORE(x) ((x) << S_TX_MORE)
+#define F_TX_MORE    V_TX_MORE(1U)
+
+/* additional tx_data_wr.flags fields */
+#define S_TX_CPU_IDX    0
+#define M_TX_CPU_IDX    0x3F
+#define V_TX_CPU_IDX(x) ((x) << S_TX_CPU_IDX)
+#define G_TX_CPU_IDX(x) (((x) >> S_TX_CPU_IDX) & M_TX_CPU_IDX)
+
+#define S_TX_URG    16
+#define V_TX_URG(x) ((x) << S_TX_URG)
+#define F_TX_URG    V_TX_URG(1U)
+
+#define S_TX_CLOSE    17
+#define V_TX_CLOSE(x) ((x) << S_TX_CLOSE)
+#define F_TX_CLOSE    V_TX_CLOSE(1U)
+
+#define S_TX_INIT    18
+#define V_TX_INIT(x) ((x) << S_TX_INIT)
+#define F_TX_INIT    V_TX_INIT(1U)
+
+#define S_TX_IMM_ACK    19
+#define V_TX_IMM_ACK(x) ((x) << S_TX_IMM_ACK)
+#define F_TX_IMM_ACK    V_TX_IMM_ACK(1U)
+
+#define S_TX_IMM_DMA    20
+#define V_TX_IMM_DMA(x) ((x) << S_TX_IMM_DMA)
+#define F_TX_IMM_DMA    V_TX_IMM_DMA(1U)
+
+struct cpl_tx_data_ack {
+       RSS_HDR union opcode_tid ot;
+       __be32 ack_seq;
+};
+
+struct cpl_wr_ack {
+       RSS_HDR union opcode_tid ot;
+       __be16 credits;
+       __be16 rsvd;
+       __be32 snd_nxt;
+       __be32 snd_una;
+};
+
+struct cpl_rdma_ec_status {
+       RSS_HDR union opcode_tid ot;
+       __u8 rsvd[3];
+       __u8 status;
+};
+
+struct mngt_pktsched_wr {
+       __be32 wr_hi;
+       __be32 wr_lo;
+       __u8 mngt_opcode;
+       __u8 rsvd[7];
+       __u8 sched;
+       __u8 idx;
+       __u8 min;
+       __u8 max;
+       __u8 binding;
+       __u8 rsvd1[3];
+};
+
+struct cpl_iscsi_hdr {
+       RSS_HDR union opcode_tid ot;
+       __be16 pdu_len_ddp;
+       __be16 len;
+       __be32 seq;
+       __be16 urg;
+       __u8 rsvd;
+       __u8 status;
+};
+
+/* cpl_iscsi_hdr.pdu_len_ddp fields */
+#define S_ISCSI_PDU_LEN    0
+#define M_ISCSI_PDU_LEN    0x7FFF
+#define V_ISCSI_PDU_LEN(x) ((x) << S_ISCSI_PDU_LEN)
+#define G_ISCSI_PDU_LEN(x) (((x) >> S_ISCSI_PDU_LEN) & M_ISCSI_PDU_LEN)
+
+#define S_ISCSI_DDP    15
+#define V_ISCSI_DDP(x) ((x) << S_ISCSI_DDP)
+#define F_ISCSI_DDP    V_ISCSI_DDP(1U)
+
+struct cpl_rx_data {
+       RSS_HDR union opcode_tid ot;
+       __be16 rsvd;
+       __be16 len;
+       __be32 seq;
+       __be16 urg;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8 dack_mode:2;
+       __u8 psh:1;
+       __u8 heartbeat:1;
+        __u8:4;
+#else
+        __u8:4;
+       __u8 heartbeat:1;
+       __u8 psh:1;
+       __u8 dack_mode:2;
+#endif
+       __u8 status;
+};
+
+struct cpl_rx_data_ack {
+       WR_HDR;
+       union opcode_tid ot;
+       __be32 credit_dack;
+};
+
+/* cpl_rx_data_ack.ack_seq fields */
+#define S_RX_CREDITS    0
+#define M_RX_CREDITS    0x7FFFFFF
+#define V_RX_CREDITS(x) ((x) << S_RX_CREDITS)
+#define G_RX_CREDITS(x) (((x) >> S_RX_CREDITS) & M_RX_CREDITS)
+
+#define S_RX_MODULATE    27
+#define V_RX_MODULATE(x) ((x) << S_RX_MODULATE)
+#define F_RX_MODULATE    V_RX_MODULATE(1U)
+
+#define S_RX_FORCE_ACK    28
+#define V_RX_FORCE_ACK(x) ((x) << S_RX_FORCE_ACK)
+#define F_RX_FORCE_ACK    V_RX_FORCE_ACK(1U)
+
+#define S_RX_DACK_MODE    29
+#define M_RX_DACK_MODE    0x3
+#define V_RX_DACK_MODE(x) ((x) << S_RX_DACK_MODE)
+#define G_RX_DACK_MODE(x) (((x) >> S_RX_DACK_MODE) & M_RX_DACK_MODE)
+
+#define S_RX_DACK_CHANGE    31
+#define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE)
+#define F_RX_DACK_CHANGE    V_RX_DACK_CHANGE(1U)
+
+struct cpl_rx_urg_notify {
+       RSS_HDR union opcode_tid ot;
+       __be32 seq;
+};
+
+struct cpl_rx_ddp_complete {
+       RSS_HDR union opcode_tid ot;
+       __be32 ddp_report;
+};
+
+struct cpl_rx_data_ddp {
+       RSS_HDR union opcode_tid ot;
+       __be16 urg;
+       __be16 len;
+       __be32 seq;
+       union {
+               __be32 nxt_seq;
+               __be32 ddp_report;
+       };
+       __be32 ulp_crc;
+       __be32 ddpvld_status;
+};
+
+/* cpl_rx_data_ddp.ddpvld_status fields */
+#define S_DDP_STATUS    0
+#define M_DDP_STATUS    0xFF
+#define V_DDP_STATUS(x) ((x) << S_DDP_STATUS)
+#define G_DDP_STATUS(x) (((x) >> S_DDP_STATUS) & M_DDP_STATUS)
+
+#define S_DDP_VALID    15
+#define M_DDP_VALID    0x1FFFF
+#define V_DDP_VALID(x) ((x) << S_DDP_VALID)
+#define G_DDP_VALID(x) (((x) >> S_DDP_VALID) & M_DDP_VALID)
+
+#define S_DDP_PPOD_MISMATCH    15
+#define V_DDP_PPOD_MISMATCH(x) ((x) << S_DDP_PPOD_MISMATCH)
+#define F_DDP_PPOD_MISMATCH    V_DDP_PPOD_MISMATCH(1U)
+
+#define S_DDP_PDU    16
+#define V_DDP_PDU(x) ((x) << S_DDP_PDU)
+#define F_DDP_PDU    V_DDP_PDU(1U)
+
+#define S_DDP_LLIMIT_ERR    17
+#define V_DDP_LLIMIT_ERR(x) ((x) << S_DDP_LLIMIT_ERR)
+#define F_DDP_LLIMIT_ERR    V_DDP_LLIMIT_ERR(1U)
+
+#define S_DDP_PPOD_PARITY_ERR    18
+#define V_DDP_PPOD_PARITY_ERR(x) ((x) << S_DDP_PPOD_PARITY_ERR)
+#define F_DDP_PPOD_PARITY_ERR    V_DDP_PPOD_PARITY_ERR(1U)
+
+#define S_DDP_PADDING_ERR    19
+#define V_DDP_PADDING_ERR(x) ((x) << S_DDP_PADDING_ERR)
+#define F_DDP_PADDING_ERR    V_DDP_PADDING_ERR(1U)
+
+#define S_DDP_HDRCRC_ERR    20
+#define V_DDP_HDRCRC_ERR(x) ((x) << S_DDP_HDRCRC_ERR)
+#define F_DDP_HDRCRC_ERR    V_DDP_HDRCRC_ERR(1U)
+
+#define S_DDP_DATACRC_ERR    21
+#define V_DDP_DATACRC_ERR(x) ((x) << S_DDP_DATACRC_ERR)
+#define F_DDP_DATACRC_ERR    V_DDP_DATACRC_ERR(1U)
+
+#define S_DDP_INVALID_TAG    22
+#define V_DDP_INVALID_TAG(x) ((x) << S_DDP_INVALID_TAG)
+#define F_DDP_INVALID_TAG    V_DDP_INVALID_TAG(1U)
+
+#define S_DDP_ULIMIT_ERR    23
+#define V_DDP_ULIMIT_ERR(x) ((x) << S_DDP_ULIMIT_ERR)
+#define F_DDP_ULIMIT_ERR    V_DDP_ULIMIT_ERR(1U)
+
+#define S_DDP_OFFSET_ERR    24
+#define V_DDP_OFFSET_ERR(x) ((x) << S_DDP_OFFSET_ERR)
+#define F_DDP_OFFSET_ERR    V_DDP_OFFSET_ERR(1U)
+
+#define S_DDP_COLOR_ERR    25
+#define V_DDP_COLOR_ERR(x) ((x) << S_DDP_COLOR_ERR)
+#define F_DDP_COLOR_ERR    V_DDP_COLOR_ERR(1U)
+
+#define S_DDP_TID_MISMATCH    26
+#define V_DDP_TID_MISMATCH(x) ((x) << S_DDP_TID_MISMATCH)
+#define F_DDP_TID_MISMATCH    V_DDP_TID_MISMATCH(1U)
+
+#define S_DDP_INVALID_PPOD    27
+#define V_DDP_INVALID_PPOD(x) ((x) << S_DDP_INVALID_PPOD)
+#define F_DDP_INVALID_PPOD    V_DDP_INVALID_PPOD(1U)
+
+#define S_DDP_ULP_MODE    28
+#define M_DDP_ULP_MODE    0xF
+#define V_DDP_ULP_MODE(x) ((x) << S_DDP_ULP_MODE)
+#define G_DDP_ULP_MODE(x) (((x) >> S_DDP_ULP_MODE) & M_DDP_ULP_MODE)
+
+/* cpl_rx_data_ddp.ddp_report fields */
+#define S_DDP_OFFSET    0
+#define M_DDP_OFFSET    0x3FFFFF
+#define V_DDP_OFFSET(x) ((x) << S_DDP_OFFSET)
+#define G_DDP_OFFSET(x) (((x) >> S_DDP_OFFSET) & M_DDP_OFFSET)
+
+#define S_DDP_URG    24
+#define V_DDP_URG(x) ((x) << S_DDP_URG)
+#define F_DDP_URG    V_DDP_URG(1U)
+
+#define S_DDP_PSH    25
+#define V_DDP_PSH(x) ((x) << S_DDP_PSH)
+#define F_DDP_PSH    V_DDP_PSH(1U)
+
+#define S_DDP_BUF_COMPLETE    26
+#define V_DDP_BUF_COMPLETE(x) ((x) << S_DDP_BUF_COMPLETE)
+#define F_DDP_BUF_COMPLETE    V_DDP_BUF_COMPLETE(1U)
+
+#define S_DDP_BUF_TIMED_OUT    27
+#define V_DDP_BUF_TIMED_OUT(x) ((x) << S_DDP_BUF_TIMED_OUT)
+#define F_DDP_BUF_TIMED_OUT    V_DDP_BUF_TIMED_OUT(1U)
+
+#define S_DDP_BUF_IDX    28
+#define V_DDP_BUF_IDX(x) ((x) << S_DDP_BUF_IDX)
+#define F_DDP_BUF_IDX    V_DDP_BUF_IDX(1U)
+
+struct cpl_tx_pkt {
+       WR_HDR;
+       __be32 cntrl;
+       __be32 len;
+};
+
+struct cpl_tx_pkt_lso {
+       WR_HDR;
+       __be32 cntrl;
+       __be32 len;
+
+       __be32 rsvd;
+       __be32 lso_info;
+};
+
+/* cpl_tx_pkt*.cntrl fields */
+#define S_TXPKT_VLAN    0
+#define M_TXPKT_VLAN    0xFFFF
+#define V_TXPKT_VLAN(x) ((x) << S_TXPKT_VLAN)
+#define G_TXPKT_VLAN(x) (((x) >> S_TXPKT_VLAN) & M_TXPKT_VLAN)
+
+#define S_TXPKT_INTF    16
+#define M_TXPKT_INTF    0xF
+#define V_TXPKT_INTF(x) ((x) << S_TXPKT_INTF)
+#define G_TXPKT_INTF(x) (((x) >> S_TXPKT_INTF) & M_TXPKT_INTF)
+
+#define S_TXPKT_IPCSUM_DIS    20
+#define V_TXPKT_IPCSUM_DIS(x) ((x) << S_TXPKT_IPCSUM_DIS)
+#define F_TXPKT_IPCSUM_DIS    V_TXPKT_IPCSUM_DIS(1U)
+
+#define S_TXPKT_L4CSUM_DIS    21
+#define V_TXPKT_L4CSUM_DIS(x) ((x) << S_TXPKT_L4CSUM_DIS)
+#define F_TXPKT_L4CSUM_DIS    V_TXPKT_L4CSUM_DIS(1U)
+
+#define S_TXPKT_VLAN_VLD    22
+#define V_TXPKT_VLAN_VLD(x) ((x) << S_TXPKT_VLAN_VLD)
+#define F_TXPKT_VLAN_VLD    V_TXPKT_VLAN_VLD(1U)
+
+#define S_TXPKT_LOOPBACK    23
+#define V_TXPKT_LOOPBACK(x) ((x) << S_TXPKT_LOOPBACK)
+#define F_TXPKT_LOOPBACK    V_TXPKT_LOOPBACK(1U)
+
+#define S_TXPKT_OPCODE    24
+#define M_TXPKT_OPCODE    0xFF
+#define V_TXPKT_OPCODE(x) ((x) << S_TXPKT_OPCODE)
+#define G_TXPKT_OPCODE(x) (((x) >> S_TXPKT_OPCODE) & M_TXPKT_OPCODE)
+
+/* cpl_tx_pkt_lso.lso_info fields */
+#define S_LSO_MSS    0
+#define M_LSO_MSS    0x3FFF
+#define V_LSO_MSS(x) ((x) << S_LSO_MSS)
+#define G_LSO_MSS(x) (((x) >> S_LSO_MSS) & M_LSO_MSS)
+
+#define S_LSO_ETH_TYPE    14
+#define M_LSO_ETH_TYPE    0x3
+#define V_LSO_ETH_TYPE(x) ((x) << S_LSO_ETH_TYPE)
+#define G_LSO_ETH_TYPE(x) (((x) >> S_LSO_ETH_TYPE) & M_LSO_ETH_TYPE)
+
+#define S_LSO_TCPHDR_WORDS    16
+#define M_LSO_TCPHDR_WORDS    0xF
+#define V_LSO_TCPHDR_WORDS(x) ((x) << S_LSO_TCPHDR_WORDS)
+#define G_LSO_TCPHDR_WORDS(x) (((x) >> S_LSO_TCPHDR_WORDS) & M_LSO_TCPHDR_WORDS)
+
+#define S_LSO_IPHDR_WORDS    20
+#define M_LSO_IPHDR_WORDS    0xF
+#define V_LSO_IPHDR_WORDS(x) ((x) << S_LSO_IPHDR_WORDS)
+#define G_LSO_IPHDR_WORDS(x) (((x) >> S_LSO_IPHDR_WORDS) & M_LSO_IPHDR_WORDS)
+
+#define S_LSO_IPV6    24
+#define V_LSO_IPV6(x) ((x) << S_LSO_IPV6)
+#define F_LSO_IPV6    V_LSO_IPV6(1U)
+
+struct cpl_trace_pkt {
+#ifdef CHELSIO_FW
+       __u8 rss_opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8 err:1;
+        __u8:7;
+#else
+        __u8:7;
+       __u8 err:1;
+#endif
+       __u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8 qid:4;
+        __u8:4;
+#else
+        __u8:4;
+       __u8 qid:4;
+#endif
+       __be32 tstamp;
+#endif                         /* CHELSIO_FW */
+
+       __u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8 iff:4;
+        __u8:4;
+#else
+        __u8:4;
+       __u8 iff:4;
+#endif
+       __u8 rsvd[4];
+       __be16 len;
+};
+
+struct cpl_rx_pkt {
+       RSS_HDR __u8 opcode;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8 iff:4;
+       __u8 csum_valid:1;
+       __u8 ipmi_pkt:1;
+       __u8 vlan_valid:1;
+       __u8 fragment:1;
+#else
+       __u8 fragment:1;
+       __u8 vlan_valid:1;
+       __u8 ipmi_pkt:1;
+       __u8 csum_valid:1;
+       __u8 iff:4;
+#endif
+       __be16 csum;
+       __be16 vlan;
+       __be16 len;
+};
+
+struct cpl_l2t_write_req {
+       WR_HDR;
+       union opcode_tid ot;
+       __be32 params;
+       __u8 rsvd[2];
+       __u8 dst_mac[6];
+};
+
+/* cpl_l2t_write_req.params fields */
+#define S_L2T_W_IDX    0
+#define M_L2T_W_IDX    0x7FF
+#define V_L2T_W_IDX(x) ((x) << S_L2T_W_IDX)
+#define G_L2T_W_IDX(x) (((x) >> S_L2T_W_IDX) & M_L2T_W_IDX)
+
+#define S_L2T_W_VLAN    11
+#define M_L2T_W_VLAN    0xFFF
+#define V_L2T_W_VLAN(x) ((x) << S_L2T_W_VLAN)
+#define G_L2T_W_VLAN(x) (((x) >> S_L2T_W_VLAN) & M_L2T_W_VLAN)
+
+#define S_L2T_W_IFF    23
+#define M_L2T_W_IFF    0xF
+#define V_L2T_W_IFF(x) ((x) << S_L2T_W_IFF)
+#define G_L2T_W_IFF(x) (((x) >> S_L2T_W_IFF) & M_L2T_W_IFF)
+
+#define S_L2T_W_PRIO    27
+#define M_L2T_W_PRIO    0x7
+#define V_L2T_W_PRIO(x) ((x) << S_L2T_W_PRIO)
+#define G_L2T_W_PRIO(x) (((x) >> S_L2T_W_PRIO) & M_L2T_W_PRIO)
+
+struct cpl_l2t_write_rpl {
+       RSS_HDR union opcode_tid ot;
+       __u8 status;
+       __u8 rsvd[3];
+};
+
+struct cpl_l2t_read_req {
+       WR_HDR;
+       union opcode_tid ot;
+       __be16 rsvd;
+       __be16 l2t_idx;
+};
+
+struct cpl_l2t_read_rpl {
+       RSS_HDR union opcode_tid ot;
+       __be32 params;
+       __u8 rsvd[2];
+       __u8 dst_mac[6];
+};
+
+/* cpl_l2t_read_rpl.params fields */
+#define S_L2T_R_PRIO    0
+#define M_L2T_R_PRIO    0x7
+#define V_L2T_R_PRIO(x) ((x) << S_L2T_R_PRIO)
+#define G_L2T_R_PRIO(x) (((x) >> S_L2T_R_PRIO) & M_L2T_R_PRIO)
+
+#define S_L2T_R_VLAN    8
+#define M_L2T_R_VLAN    0xFFF
+#define V_L2T_R_VLAN(x) ((x) << S_L2T_R_VLAN)
+#define G_L2T_R_VLAN(x) (((x) >> S_L2T_R_VLAN) & M_L2T_R_VLAN)
+
+#define S_L2T_R_IFF    20
+#define M_L2T_R_IFF    0xF
+#define V_L2T_R_IFF(x) ((x) << S_L2T_R_IFF)
+#define G_L2T_R_IFF(x) (((x) >> S_L2T_R_IFF) & M_L2T_R_IFF)
+
+#define S_L2T_STATUS    24
+#define M_L2T_STATUS    0xFF
+#define V_L2T_STATUS(x) ((x) << S_L2T_STATUS)
+#define G_L2T_STATUS(x) (((x) >> S_L2T_STATUS) & M_L2T_STATUS)
+
+struct cpl_smt_write_req {
+       WR_HDR;
+       union opcode_tid ot;
+       __u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8 mtu_idx:4;
+       __u8 iff:4;
+#else
+       __u8 iff:4;
+       __u8 mtu_idx:4;
+#endif
+       __be16 rsvd2;
+       __be16 rsvd3;
+       __u8 src_mac1[6];
+       __be16 rsvd4;
+       __u8 src_mac0[6];
+};
+
+struct cpl_smt_write_rpl {
+       RSS_HDR union opcode_tid ot;
+       __u8 status;
+       __u8 rsvd[3];
+};
+
+struct cpl_smt_read_req {
+       WR_HDR;
+       union opcode_tid ot;
+       __u8 rsvd0;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+        __u8:4;
+       __u8 iff:4;
+#else
+       __u8 iff:4;
+        __u8:4;
+#endif
+       __be16 rsvd2;
+};
+
+struct cpl_smt_read_rpl {
+       RSS_HDR union opcode_tid ot;
+       __u8 status;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8 mtu_idx:4;
+        __u8:4;
+#else
+        __u8:4;
+       __u8 mtu_idx:4;
+#endif
+       __be16 rsvd2;
+       __be16 rsvd3;
+       __u8 src_mac1[6];
+       __be16 rsvd4;
+       __u8 src_mac0[6];
+};
+
+struct cpl_rte_delete_req {
+       WR_HDR;
+       union opcode_tid ot;
+       __be32 params;
+};
+
+/* { cpl_rte_delete_req, cpl_rte_read_req }.params fields */
+#define S_RTE_REQ_LUT_IX    8
+#define M_RTE_REQ_LUT_IX    0x7FF
+#define V_RTE_REQ_LUT_IX(x) ((x) << S_RTE_REQ_LUT_IX)
+#define G_RTE_REQ_LUT_IX(x) (((x) >> S_RTE_REQ_LUT_IX) & M_RTE_REQ_LUT_IX)
+
+#define S_RTE_REQ_LUT_BASE    19
+#define M_RTE_REQ_LUT_BASE    0x7FF
+#define V_RTE_REQ_LUT_BASE(x) ((x) << S_RTE_REQ_LUT_BASE)
+#define G_RTE_REQ_LUT_BASE(x) (((x) >> S_RTE_REQ_LUT_BASE) & M_RTE_REQ_LUT_BASE)
+
+#define S_RTE_READ_REQ_SELECT    31
+#define V_RTE_READ_REQ_SELECT(x) ((x) << S_RTE_READ_REQ_SELECT)
+#define F_RTE_READ_REQ_SELECT    V_RTE_READ_REQ_SELECT(1U)
+
+struct cpl_rte_delete_rpl {
+       RSS_HDR union opcode_tid ot;
+       __u8 status;
+       __u8 rsvd[3];
+};
+
+struct cpl_rte_write_req {
+       WR_HDR;
+       union opcode_tid ot;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+        __u8:6;
+       __u8 write_tcam:1;
+       __u8 write_l2t_lut:1;
+#else
+       __u8 write_l2t_lut:1;
+       __u8 write_tcam:1;
+        __u8:6;
+#endif
+       __u8 rsvd[3];
+       __be32 lut_params;
+       __be16 rsvd2;
+       __be16 l2t_idx;
+       __be32 netmask;
+       __be32 faddr;
+};
+
+/* cpl_rte_write_req.lut_params fields */
+#define S_RTE_WRITE_REQ_LUT_IX    10
+#define M_RTE_WRITE_REQ_LUT_IX    0x7FF
+#define V_RTE_WRITE_REQ_LUT_IX(x) ((x) << S_RTE_WRITE_REQ_LUT_IX)
+#define G_RTE_WRITE_REQ_LUT_IX(x) (((x) >> S_RTE_WRITE_REQ_LUT_IX) & M_RTE_WRITE_REQ_LUT_IX)
+
+#define S_RTE_WRITE_REQ_LUT_BASE    21
+#define M_RTE_WRITE_REQ_LUT_BASE    0x7FF
+#define V_RTE_WRITE_REQ_LUT_BASE(x) ((x) << S_RTE_WRITE_REQ_LUT_BASE)
+#define G_RTE_WRITE_REQ_LUT_BASE(x) (((x) >> S_RTE_WRITE_REQ_LUT_BASE) & M_RTE_WRITE_REQ_LUT_BASE)
+
+struct cpl_rte_write_rpl {
+       RSS_HDR union opcode_tid ot;
+       __u8 status;
+       __u8 rsvd[3];
+};
+
+struct cpl_rte_read_req {
+       WR_HDR;
+       union opcode_tid ot;
+       __be32 params;
+};
+
+struct cpl_rte_read_rpl {
+       RSS_HDR union opcode_tid ot;
+       __u8 status;
+       __u8 rsvd0;
+       __be16 l2t_idx;
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+        __u8:7;
+       __u8 select:1;
+#else
+       __u8 select:1;
+        __u8:7;
+#endif
+       __u8 rsvd2[3];
+       __be32 addr;
+};
+
+struct cpl_tid_release {
+       WR_HDR;
+       union opcode_tid ot;
+       __be32 rsvd;
+};
+
+struct cpl_barrier {
+       WR_HDR;
+       __u8 opcode;
+       __u8 rsvd[7];
+};
+
+struct cpl_rdma_read_req {
+       __u8 opcode;
+       __u8 rsvd[15];
+};
+
+struct cpl_rdma_terminate {
+#ifdef CHELSIO_FW
+       __u8 opcode;
+       __u8 rsvd[2];
+#if defined(__LITTLE_ENDIAN_BITFIELD)
+       __u8 rspq:3;
+        __u8:5;
+#else
+        __u8:5;
+       __u8 rspq:3;
+#endif
+       __be32 tid_len;
+#endif
+       __be32 msn;
+       __be32 mo;
+       __u8 data[0];
+};
+
+/* cpl_rdma_terminate.tid_len fields */
+#define S_FLIT_CNT    0
+#define M_FLIT_CNT    0xFF
+#define V_FLIT_CNT(x) ((x) << S_FLIT_CNT)
+#define G_FLIT_CNT(x) (((x) >> S_FLIT_CNT) & M_FLIT_CNT)
+
+#define S_TERM_TID    8
+#define M_TERM_TID    0xFFFFF
+#define V_TERM_TID(x) ((x) << S_TERM_TID)
+#define G_TERM_TID(x) (((x) >> S_TERM_TID) & M_TERM_TID)
+#endif                         /* T3_CPL_H */
diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c
new file mode 100644 (file)
index 0000000..365a7f5
--- /dev/null
@@ -0,0 +1,3375 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+#include "sge_defs.h"
+#include "firmware_exports.h"
+
+/**
+ *     t3_wait_op_done_val - wait until an operation is completed
+ *     @adapter: the adapter performing the operation
+ *     @reg: the register to check for completion
+ *     @mask: a single-bit field within @reg that indicates completion
+ *     @polarity: the value of the field when the operation is completed
+ *     @attempts: number of check iterations
+ *     @delay: delay in usecs between iterations
+ *     @valp: where to store the value of the register at completion time
+ *
+ *     Wait until an operation is completed by checking a bit in a register
+ *     up to @attempts times.  If @valp is not NULL the value of the register
+ *     at the time it indicated completion is stored there.  Returns 0 if the
+ *     operation completes and -EAGAIN otherwise.
+ */
+
+int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
+                       int polarity, int attempts, int delay, u32 *valp)
+{
+       while (1) {
+               u32 val = t3_read_reg(adapter, reg);
+
+               if (!!(val & mask) == polarity) {
+                       if (valp)
+                               *valp = val;
+                       return 0;
+               }
+               if (--attempts == 0)
+                       return -EAGAIN;
+               if (delay)
+                       udelay(delay);
+       }
+}
+
+/**
+ *     t3_write_regs - write a bunch of registers
+ *     @adapter: the adapter to program
+ *     @p: an array of register address/register value pairs
+ *     @n: the number of address/value pairs
+ *     @offset: register address offset
+ *
+ *     Takes an array of register address/register value pairs and writes each
+ *     value to the corresponding register.  Register addresses are adjusted
+ *     by the supplied offset.
+ */
+void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p,
+                  int n, unsigned int offset)
+{
+       while (n--) {
+               t3_write_reg(adapter, p->reg_addr + offset, p->val);
+               p++;
+       }
+}
+
+/**
+ *     t3_set_reg_field - set a register field to a value
+ *     @adapter: the adapter to program
+ *     @addr: the register address
+ *     @mask: specifies the portion of the register to modify
+ *     @val: the new value for the register field
+ *
+ *     Sets a register field specified by the supplied mask to the
+ *     given value.
+ */
+void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
+                     u32 val)
+{
+       u32 v = t3_read_reg(adapter, addr) & ~mask;
+
+       t3_write_reg(adapter, addr, v | val);
+       t3_read_reg(adapter, addr);     /* flush */
+}
+
+/**
+ *     t3_read_indirect - read indirectly addressed registers
+ *     @adap: the adapter
+ *     @addr_reg: register holding the indirect address
+ *     @data_reg: register holding the value of the indirect register
+ *     @vals: where the read register values are stored
+ *     @start_idx: index of first indirect register to read
+ *     @nregs: how many indirect registers to read
+ *
+ *     Reads registers that are accessed indirectly through an address/data
+ *     register pair.
+ */
+void t3_read_indirect(struct adapter *adap, unsigned int addr_reg,
+                     unsigned int data_reg, u32 *vals, unsigned int nregs,
+                     unsigned int start_idx)
+{
+       while (nregs--) {
+               t3_write_reg(adap, addr_reg, start_idx);
+               *vals++ = t3_read_reg(adap, data_reg);
+               start_idx++;
+       }
+}
+
+/**
+ *     t3_mc7_bd_read - read from MC7 through backdoor accesses
+ *     @mc7: identifies MC7 to read from
+ *     @start: index of first 64-bit word to read
+ *     @n: number of 64-bit words to read
+ *     @buf: where to store the read result
+ *
+ *     Read n 64-bit words from MC7 starting at word start, using backdoor
+ *     accesses.
+ */
+int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
+                  u64 *buf)
+{
+       static const int shift[] = { 0, 0, 16, 24 };
+       static const int step[] = { 0, 32, 16, 8 };
+
+       unsigned int size64 = mc7->size / 8;    /* # of 64-bit words */
+       struct adapter *adap = mc7->adapter;
+
+       if (start >= size64 || start + n > size64)
+               return -EINVAL;
+
+       start *= (8 << mc7->width);
+       while (n--) {
+               int i;
+               u64 val64 = 0;
+
+               for (i = (1 << mc7->width) - 1; i >= 0; --i) {
+                       int attempts = 10;
+                       u32 val;
+
+                       t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR, start);
+                       t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0);
+                       val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP);
+                       while ((val & F_BUSY) && attempts--)
+                               val = t3_read_reg(adap,
+                                                 mc7->offset + A_MC7_BD_OP);
+                       if (val & F_BUSY)
+                               return -EIO;
+
+                       val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1);
+                       if (mc7->width == 0) {
+                               val64 = t3_read_reg(adap,
+                                                   mc7->offset +
+                                                   A_MC7_BD_DATA0);
+                               val64 |= (u64) val << 32;
+                       } else {
+                               if (mc7->width > 1)
+                                       val >>= shift[mc7->width];
+                               val64 |= (u64) val << (step[mc7->width] * i);
+                       }
+                       start += 8;
+               }
+               *buf++ = val64;
+       }
+       return 0;
+}
+
+/*
+ * Initialize MI1.
+ */
+static void mi1_init(struct adapter *adap, const struct adapter_info *ai)
+{
+       u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1;
+       u32 val = F_PREEN | V_MDIINV(ai->mdiinv) | V_MDIEN(ai->mdien) |
+           V_CLKDIV(clkdiv);
+
+       if (!(ai->caps & SUPPORTED_10000baseT_Full))
+               val |= V_ST(1);
+       t3_write_reg(adap, A_MI1_CFG, val);
+}
+
+#define MDIO_ATTEMPTS 10
+
+/*
+ * MI1 read/write operations for direct-addressed PHYs.
+ */
+static int mi1_read(struct adapter *adapter, int phy_addr, int mmd_addr,
+                   int reg_addr, unsigned int *valp)
+{
+       int ret;
+       u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
+
+       if (mmd_addr)
+               return -EINVAL;
+
+       mutex_lock(&adapter->mdio_lock);
+       t3_write_reg(adapter, A_MI1_ADDR, addr);
+       t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2));
+       ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+       if (!ret)
+               *valp = t3_read_reg(adapter, A_MI1_DATA);
+       mutex_unlock(&adapter->mdio_lock);
+       return ret;
+}
+
+static int mi1_write(struct adapter *adapter, int phy_addr, int mmd_addr,
+                    int reg_addr, unsigned int val)
+{
+       int ret;
+       u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
+
+       if (mmd_addr)
+               return -EINVAL;
+
+       mutex_lock(&adapter->mdio_lock);
+       t3_write_reg(adapter, A_MI1_ADDR, addr);
+       t3_write_reg(adapter, A_MI1_DATA, val);
+       t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
+       ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+       mutex_unlock(&adapter->mdio_lock);
+       return ret;
+}
+
+static const struct mdio_ops mi1_mdio_ops = {
+       mi1_read,
+       mi1_write
+};
+
+/*
+ * MI1 read/write operations for indirect-addressed PHYs.
+ */
+static int mi1_ext_read(struct adapter *adapter, int phy_addr, int mmd_addr,
+                       int reg_addr, unsigned int *valp)
+{
+       int ret;
+       u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
+
+       mutex_lock(&adapter->mdio_lock);
+       t3_write_reg(adapter, A_MI1_ADDR, addr);
+       t3_write_reg(adapter, A_MI1_DATA, reg_addr);
+       t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
+       ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+       if (!ret) {
+               t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3));
+               ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
+                                     MDIO_ATTEMPTS, 20);
+               if (!ret)
+                       *valp = t3_read_reg(adapter, A_MI1_DATA);
+       }
+       mutex_unlock(&adapter->mdio_lock);
+       return ret;
+}
+
+static int mi1_ext_write(struct adapter *adapter, int phy_addr, int mmd_addr,
+                        int reg_addr, unsigned int val)
+{
+       int ret;
+       u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
+
+       mutex_lock(&adapter->mdio_lock);
+       t3_write_reg(adapter, A_MI1_ADDR, addr);
+       t3_write_reg(adapter, A_MI1_DATA, reg_addr);
+       t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
+       ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 20);
+       if (!ret) {
+               t3_write_reg(adapter, A_MI1_DATA, val);
+               t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
+               ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
+                                     MDIO_ATTEMPTS, 20);
+       }
+       mutex_unlock(&adapter->mdio_lock);
+       return ret;
+}
+
+static const struct mdio_ops mi1_mdio_ext_ops = {
+       mi1_ext_read,
+       mi1_ext_write
+};
+
+/**
+ *     t3_mdio_change_bits - modify the value of a PHY register
+ *     @phy: the PHY to operate on
+ *     @mmd: the device address
+ *     @reg: the register address
+ *     @clear: what part of the register value to mask off
+ *     @set: what part of the register value to set
+ *
+ *     Changes the value of a PHY register by applying a mask to its current
+ *     value and ORing the result with a new value.
+ */
+int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
+                       unsigned int set)
+{
+       int ret;
+       unsigned int val;
+
+       ret = mdio_read(phy, mmd, reg, &val);
+       if (!ret) {
+               val &= ~clear;
+               ret = mdio_write(phy, mmd, reg, val | set);
+       }
+       return ret;
+}
+
+/**
+ *     t3_phy_reset - reset a PHY block
+ *     @phy: the PHY to operate on
+ *     @mmd: the device address of the PHY block to reset
+ *     @wait: how long to wait for the reset to complete in 1ms increments
+ *
+ *     Resets a PHY block and optionally waits for the reset to complete.
+ *     @mmd should be 0 for 10/100/1000 PHYs and the device address to reset
+ *     for 10G PHYs.
+ */
+int t3_phy_reset(struct cphy *phy, int mmd, int wait)
+{
+       int err;
+       unsigned int ctl;
+
+       err = t3_mdio_change_bits(phy, mmd, MII_BMCR, BMCR_PDOWN, BMCR_RESET);
+       if (err || !wait)
+               return err;
+
+       do {
+               err = mdio_read(phy, mmd, MII_BMCR, &ctl);
+               if (err)
+                       return err;
+               ctl &= BMCR_RESET;
+               if (ctl)
+                       msleep(1);
+       } while (ctl && --wait);
+
+       return ctl ? -1 : 0;
+}
+
+/**
+ *     t3_phy_advertise - set the PHY advertisement registers for autoneg
+ *     @phy: the PHY to operate on
+ *     @advert: bitmap of capabilities the PHY should advertise
+ *
+ *     Sets a 10/100/1000 PHY's advertisement registers to advertise the
+ *     requested capabilities.
+ */
+int t3_phy_advertise(struct cphy *phy, unsigned int advert)
+{
+       int err;
+       unsigned int val = 0;
+
+       err = mdio_read(phy, 0, MII_CTRL1000, &val);
+       if (err)
+               return err;
+
+       val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
+       if (advert & ADVERTISED_1000baseT_Half)
+               val |= ADVERTISE_1000HALF;
+       if (advert & ADVERTISED_1000baseT_Full)
+               val |= ADVERTISE_1000FULL;
+
+       err = mdio_write(phy, 0, MII_CTRL1000, val);
+       if (err)
+               return err;
+
+       val = 1;
+       if (advert & ADVERTISED_10baseT_Half)
+               val |= ADVERTISE_10HALF;
+       if (advert & ADVERTISED_10baseT_Full)
+               val |= ADVERTISE_10FULL;
+       if (advert & ADVERTISED_100baseT_Half)
+               val |= ADVERTISE_100HALF;
+       if (advert & ADVERTISED_100baseT_Full)
+               val |= ADVERTISE_100FULL;
+       if (advert & ADVERTISED_Pause)
+               val |= ADVERTISE_PAUSE_CAP;
+       if (advert & ADVERTISED_Asym_Pause)
+               val |= ADVERTISE_PAUSE_ASYM;
+       return mdio_write(phy, 0, MII_ADVERTISE, val);
+}
+
+/**
+ *     t3_set_phy_speed_duplex - force PHY speed and duplex
+ *     @phy: the PHY to operate on
+ *     @speed: requested PHY speed
+ *     @duplex: requested PHY duplex
+ *
+ *     Force a 10/100/1000 PHY's speed and duplex.  This also disables
+ *     auto-negotiation except for GigE, where auto-negotiation is mandatory.
+ */
+int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex)
+{
+       int err;
+       unsigned int ctl;
+
+       err = mdio_read(phy, 0, MII_BMCR, &ctl);
+       if (err)
+               return err;
+
+       if (speed >= 0) {
+               ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
+               if (speed == SPEED_100)
+                       ctl |= BMCR_SPEED100;
+               else if (speed == SPEED_1000)
+                       ctl |= BMCR_SPEED1000;
+       }
+       if (duplex >= 0) {
+               ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
+               if (duplex == DUPLEX_FULL)
+                       ctl |= BMCR_FULLDPLX;
+       }
+       if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */
+               ctl |= BMCR_ANENABLE;
+       return mdio_write(phy, 0, MII_BMCR, ctl);
+}
+
+static const struct adapter_info t3_adap_info[] = {
+       {2, 0, 0, 0,
+        F_GPIO2_OEN | F_GPIO4_OEN |
+        F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
+        SUPPORTED_OFFLOAD,
+        &mi1_mdio_ops, "Chelsio PE9000"},
+       {2, 0, 0, 0,
+        F_GPIO2_OEN | F_GPIO4_OEN |
+        F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
+        SUPPORTED_OFFLOAD,
+        &mi1_mdio_ops, "Chelsio T302"},
+       {1, 0, 0, 0,
+        F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
+        F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
+        SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD,
+        &mi1_mdio_ext_ops, "Chelsio T310"},
+       {2, 0, 0, 0,
+        F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
+        F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
+        F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
+        SUPPORTED_10000baseT_Full | SUPPORTED_AUI | SUPPORTED_OFFLOAD,
+        &mi1_mdio_ext_ops, "Chelsio T320"},
+};
+
+/*
+ * Return the adapter_info structure with a given index.  Out-of-range indices
+ * return NULL.
+ */
+const struct adapter_info *t3_get_adapter_info(unsigned int id)
+{
+       return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL;
+}
+
+#define CAPS_1G (SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Full | \
+                SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg | SUPPORTED_MII)
+#define CAPS_10G (SUPPORTED_10000baseT_Full | SUPPORTED_AUI)
+
+static const struct port_type_info port_types[] = {
+       {NULL},
+       {t3_ael1002_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
+        "10GBASE-XR"},
+       {t3_vsc8211_phy_prep, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
+        "10/100/1000BASE-T"},
+       {NULL, CAPS_1G | SUPPORTED_TP | SUPPORTED_IRQ,
+        "10/100/1000BASE-T"},
+       {t3_xaui_direct_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+       {NULL, CAPS_10G, "10GBASE-KX4"},
+       {t3_qt2045_phy_prep, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+       {t3_ael1006_phy_prep, CAPS_10G | SUPPORTED_FIBRE,
+        "10GBASE-SR"},
+       {NULL, CAPS_10G | SUPPORTED_TP, "10GBASE-CX4"},
+};
+
+#undef CAPS_1G
+#undef CAPS_10G
+
+#define VPD_ENTRY(name, len) \
+       u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
+
+/*
+ * Partial EEPROM Vital Product Data structure.  Includes only the ID and
+ * VPD-R sections.
+ */
+struct t3_vpd {
+       u8 id_tag;
+       u8 id_len[2];
+       u8 id_data[16];
+       u8 vpdr_tag;
+       u8 vpdr_len[2];
+       VPD_ENTRY(pn, 16);      /* part number */
+       VPD_ENTRY(ec, 16);      /* EC level */
+       VPD_ENTRY(sn, 16);      /* serial number */
+       VPD_ENTRY(na, 12);      /* MAC address base */
+       VPD_ENTRY(cclk, 6);     /* core clock */
+       VPD_ENTRY(mclk, 6);     /* mem clock */
+       VPD_ENTRY(uclk, 6);     /* uP clk */
+       VPD_ENTRY(mdc, 6);      /* MDIO clk */
+       VPD_ENTRY(mt, 2);       /* mem timing */
+       VPD_ENTRY(xaui0cfg, 6); /* XAUI0 config */
+       VPD_ENTRY(xaui1cfg, 6); /* XAUI1 config */
+       VPD_ENTRY(port0, 2);    /* PHY0 complex */
+       VPD_ENTRY(port1, 2);    /* PHY1 complex */
+       VPD_ENTRY(port2, 2);    /* PHY2 complex */
+       VPD_ENTRY(port3, 2);    /* PHY3 complex */
+       VPD_ENTRY(rv, 1);       /* csum */
+       u32 pad;                /* for multiple-of-4 sizing and alignment */
+};
+
+#define EEPROM_MAX_POLL   4
+#define EEPROM_STAT_ADDR  0x4000
+#define VPD_BASE          0xc00
+
+/**
+ *     t3_seeprom_read - read a VPD EEPROM location
+ *     @adapter: adapter to read
+ *     @addr: EEPROM address
+ *     @data: where to store the read data
+ *
+ *     Read a 32-bit word from a location in VPD EEPROM using the card's PCI
+ *     VPD ROM capability.  A zero is written to the flag bit when the
+ *     addres is written to the control register.  The hardware device will
+ *     set the flag to 1 when 4 bytes have been read into the data register.
+ */
+int t3_seeprom_read(struct adapter *adapter, u32 addr, u32 *data)
+{
+       u16 val;
+       int attempts = EEPROM_MAX_POLL;
+       unsigned int base = adapter->params.pci.vpd_cap_addr;
+
+       if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
+               return -EINVAL;
+
+       pci_write_config_word(adapter->pdev, base + PCI_VPD_ADDR, addr);
+       do {
+               udelay(10);
+               pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
+       } while (!(val & PCI_VPD_ADDR_F) && --attempts);
+
+       if (!(val & PCI_VPD_ADDR_F)) {
+               CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
+               return -EIO;
+       }
+       pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, data);
+       *data = le32_to_cpu(*data);
+       return 0;
+}
+
+/**
+ *     t3_seeprom_write - write a VPD EEPROM location
+ *     @adapter: adapter to write
+ *     @addr: EEPROM address
+ *     @data: value to write
+ *
+ *     Write a 32-bit word to a location in VPD EEPROM using the card's PCI
+ *     VPD ROM capability.
+ */
+int t3_seeprom_write(struct adapter *adapter, u32 addr, u32 data)
+{
+       u16 val;
+       int attempts = EEPROM_MAX_POLL;
+       unsigned int base = adapter->params.pci.vpd_cap_addr;
+
+       if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
+               return -EINVAL;
+
+       pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA,
+                              cpu_to_le32(data));
+       pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR,
+                             addr | PCI_VPD_ADDR_F);
+       do {
+               msleep(1);
+               pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
+       } while ((val & PCI_VPD_ADDR_F) && --attempts);
+
+       if (val & PCI_VPD_ADDR_F) {
+               CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr);
+               return -EIO;
+       }
+       return 0;
+}
+
+/**
+ *     t3_seeprom_wp - enable/disable EEPROM write protection
+ *     @adapter: the adapter
+ *     @enable: 1 to enable write protection, 0 to disable it
+ *
+ *     Enables or disables write protection on the serial EEPROM.
+ */
+int t3_seeprom_wp(struct adapter *adapter, int enable)
+{
+       return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
+}
+
+/*
+ * Convert a character holding a hex digit to a number.
+ */
+static unsigned int hex2int(unsigned char c)
+{
+       return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
+}
+
+/**
+ *     get_vpd_params - read VPD parameters from VPD EEPROM
+ *     @adapter: adapter to read
+ *     @p: where to store the parameters
+ *
+ *     Reads card parameters stored in VPD EEPROM.
+ */
+static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
+{
+       int i, addr, ret;
+       struct t3_vpd vpd;
+
+       /*
+        * Card information is normally at VPD_BASE but some early cards had
+        * it at 0.
+        */
+       ret = t3_seeprom_read(adapter, VPD_BASE, (u32 *)&vpd);
+       if (ret)
+               return ret;
+       addr = vpd.id_tag == 0x82 ? VPD_BASE : 0;
+
+       for (i = 0; i < sizeof(vpd); i += 4) {
+               ret = t3_seeprom_read(adapter, addr + i,
+                                     (u32 *)((u8 *)&vpd + i));
+               if (ret)
+                       return ret;
+       }
+
+       p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10);
+       p->mclk = simple_strtoul(vpd.mclk_data, NULL, 10);
+       p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10);
+       p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10);
+       p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10);
+
+       /* Old eeproms didn't have port information */
+       if (adapter->params.rev == 0 && !vpd.port0_data[0]) {
+               p->port_type[0] = uses_xaui(adapter) ? 1 : 2;
+               p->port_type[1] = uses_xaui(adapter) ? 6 : 2;
+       } else {
+               p->port_type[0] = hex2int(vpd.port0_data[0]);
+               p->port_type[1] = hex2int(vpd.port1_data[0]);
+               p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16);
+               p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16);
+       }
+
+       for (i = 0; i < 6; i++)
+               p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 +
+                                hex2int(vpd.na_data[2 * i + 1]);
+       return 0;
+}
+
+/* serial flash and firmware constants */
+enum {
+       SF_ATTEMPTS = 5,        /* max retries for SF1 operations */
+       SF_SEC_SIZE = 64 * 1024,        /* serial flash sector size */
+       SF_SIZE = SF_SEC_SIZE * 8,      /* serial flash size */
+
+       /* flash command opcodes */
+       SF_PROG_PAGE = 2,       /* program page */
+       SF_WR_DISABLE = 4,      /* disable writes */
+       SF_RD_STATUS = 5,       /* read status register */
+       SF_WR_ENABLE = 6,       /* enable writes */
+       SF_RD_DATA_FAST = 0xb,  /* read flash */
+       SF_ERASE_SECTOR = 0xd8, /* erase sector */
+
+       FW_FLASH_BOOT_ADDR = 0x70000,   /* start address of FW in flash */
+       FW_VERS_ADDR = 0x77ffc  /* flash address holding FW version */
+};
+
+/**
+ *     sf1_read - read data from the serial flash
+ *     @adapter: the adapter
+ *     @byte_cnt: number of bytes to read
+ *     @cont: whether another operation will be chained
+ *     @valp: where to store the read data
+ *
+ *     Reads up to 4 bytes of data from the serial flash.  The location of
+ *     the read needs to be specified prior to calling this by issuing the
+ *     appropriate commands to the serial flash.
+ */
+static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
+                   u32 *valp)
+{
+       int ret;
+
+       if (!byte_cnt || byte_cnt > 4)
+               return -EINVAL;
+       if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
+               return -EBUSY;
+       t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1));
+       ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
+       if (!ret)
+               *valp = t3_read_reg(adapter, A_SF_DATA);
+       return ret;
+}
+
+/**
+ *     sf1_write - write data to the serial flash
+ *     @adapter: the adapter
+ *     @byte_cnt: number of bytes to write
+ *     @cont: whether another operation will be chained
+ *     @val: value to write
+ *
+ *     Writes up to 4 bytes of data to the serial flash.  The location of
+ *     the write needs to be specified prior to calling this by issuing the
+ *     appropriate commands to the serial flash.
+ */
+static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
+                    u32 val)
+{
+       if (!byte_cnt || byte_cnt > 4)
+               return -EINVAL;
+       if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
+               return -EBUSY;
+       t3_write_reg(adapter, A_SF_DATA, val);
+       t3_write_reg(adapter, A_SF_OP,
+                    V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1));
+       return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
+}
+
+/**
+ *     flash_wait_op - wait for a flash operation to complete
+ *     @adapter: the adapter
+ *     @attempts: max number of polls of the status register
+ *     @delay: delay between polls in ms
+ *
+ *     Wait for a flash operation to complete by polling the status register.
+ */
+static int flash_wait_op(struct adapter *adapter, int attempts, int delay)
+{
+       int ret;
+       u32 status;
+
+       while (1) {
+               if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 ||
+                   (ret = sf1_read(adapter, 1, 0, &status)) != 0)
+                       return ret;
+               if (!(status & 1))
+                       return 0;
+               if (--attempts == 0)
+                       return -EAGAIN;
+               if (delay)
+                       msleep(delay);
+       }
+}
+
+/**
+ *     t3_read_flash - read words from serial flash
+ *     @adapter: the adapter
+ *     @addr: the start address for the read
+ *     @nwords: how many 32-bit words to read
+ *     @data: where to store the read data
+ *     @byte_oriented: whether to store data as bytes or as words
+ *
+ *     Read the specified number of 32-bit words from the serial flash.
+ *     If @byte_oriented is set the read data is stored as a byte array
+ *     (i.e., big-endian), otherwise as 32-bit words in the platform's
+ *     natural endianess.
+ */
+int t3_read_flash(struct adapter *adapter, unsigned int addr,
+                 unsigned int nwords, u32 *data, int byte_oriented)
+{
+       int ret;
+
+       if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3))
+               return -EINVAL;
+
+       addr = swab32(addr) | SF_RD_DATA_FAST;
+
+       if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 ||
+           (ret = sf1_read(adapter, 1, 1, data)) != 0)
+               return ret;
+
+       for (; nwords; nwords--, data++) {
+               ret = sf1_read(adapter, 4, nwords > 1, data);
+               if (ret)
+                       return ret;
+               if (byte_oriented)
+                       *data = htonl(*data);
+       }
+       return 0;
+}
+
+/**
+ *     t3_write_flash - write up to a page of data to the serial flash
+ *     @adapter: the adapter
+ *     @addr: the start address to write
+ *     @n: length of data to write
+ *     @data: the data to write
+ *
+ *     Writes up to a page of data (256 bytes) to the serial flash starting
+ *     at the given address.
+ */
+static int t3_write_flash(struct adapter *adapter, unsigned int addr,
+                         unsigned int n, const u8 *data)
+{
+       int ret;
+       u32 buf[64];
+       unsigned int i, c, left, val, offset = addr & 0xff;
+
+       if (addr + n > SF_SIZE || offset + n > 256)
+               return -EINVAL;
+
+       val = swab32(addr) | SF_PROG_PAGE;
+
+       if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
+           (ret = sf1_write(adapter, 4, 1, val)) != 0)
+               return ret;
+
+       for (left = n; left; left -= c) {
+               c = min(left, 4U);
+               for (val = 0, i = 0; i < c; ++i)
+                       val = (val << 8) + *data++;
+
+               ret = sf1_write(adapter, c, c != left, val);
+               if (ret)
+                       return ret;
+       }
+       if ((ret = flash_wait_op(adapter, 5, 1)) != 0)
+               return ret;
+
+       /* Read the page to verify the write succeeded */
+       ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1);
+       if (ret)
+               return ret;
+
+       if (memcmp(data - n, (u8 *) buf + offset, n))
+               return -EIO;
+       return 0;
+}
+
+enum fw_version_type {
+       FW_VERSION_N3,
+       FW_VERSION_T3
+};
+
+/**
+ *     t3_get_fw_version - read the firmware version
+ *     @adapter: the adapter
+ *     @vers: where to place the version
+ *
+ *     Reads the FW version from flash.
+ */
+int t3_get_fw_version(struct adapter *adapter, u32 *vers)
+{
+       return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0);
+}
+
+/**
+ *     t3_check_fw_version - check if the FW is compatible with this driver
+ *     @adapter: the adapter
+ *
+ *     Checks if an adapter's FW is compatible with the driver.  Returns 0
+ *     if the versions are compatible, a negative error otherwise.
+ */
+int t3_check_fw_version(struct adapter *adapter)
+{
+       int ret;
+       u32 vers;
+       unsigned int type, major, minor;
+
+       ret = t3_get_fw_version(adapter, &vers);
+       if (ret)
+               return ret;
+
+       type = G_FW_VERSION_TYPE(vers);
+       major = G_FW_VERSION_MAJOR(vers);
+       minor = G_FW_VERSION_MINOR(vers);
+
+       if (type == FW_VERSION_T3 && major == 3 && minor == 1)
+               return 0;
+
+       CH_ERR(adapter, "found wrong FW version(%u.%u), "
+              "driver needs version 3.1\n", major, minor);
+       return -EINVAL;
+}
+
+/**
+ *     t3_flash_erase_sectors - erase a range of flash sectors
+ *     @adapter: the adapter
+ *     @start: the first sector to erase
+ *     @end: the last sector to erase
+ *
+ *     Erases the sectors in the given range.
+ */
+static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end)
+{
+       while (start <= end) {
+               int ret;
+
+               if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
+                   (ret = sf1_write(adapter, 4, 0,
+                                    SF_ERASE_SECTOR | (start << 8))) != 0 ||
+                   (ret = flash_wait_op(adapter, 5, 500)) != 0)
+                       return ret;
+               start++;
+       }
+       return 0;
+}
+
+/*
+ *     t3_load_fw - download firmware
+ *     @adapter: the adapter
+ *     @fw_data: the firrware image to write
+ *     @size: image size
+ *
+ *     Write the supplied firmware image to the card's serial flash.
+ *     The FW image has the following sections: @size - 8 bytes of code and
+ *     data, followed by 4 bytes of FW version, followed by the 32-bit
+ *     1's complement checksum of the whole image.
+ */
+int t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size)
+{
+       u32 csum;
+       unsigned int i;
+       const u32 *p = (const u32 *)fw_data;
+       int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16;
+
+       if (size & 3)
+               return -EINVAL;
+       if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR)
+               return -EFBIG;
+
+       for (csum = 0, i = 0; i < size / sizeof(csum); i++)
+               csum += ntohl(p[i]);
+       if (csum != 0xffffffff) {
+               CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
+                      csum);
+               return -EINVAL;
+       }
+
+       ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector);
+       if (ret)
+               goto out;
+
+       size -= 8;              /* trim off version and checksum */
+       for (addr = FW_FLASH_BOOT_ADDR; size;) {
+               unsigned int chunk_size = min(size, 256U);
+
+               ret = t3_write_flash(adapter, addr, chunk_size, fw_data);
+               if (ret)
+                       goto out;
+
+               addr += chunk_size;
+               fw_data += chunk_size;
+               size -= chunk_size;
+       }
+
+       ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data);
+out:
+       if (ret)
+               CH_ERR(adapter, "firmware download failed, error %d\n", ret);
+       return ret;
+}
+
+#define CIM_CTL_BASE 0x2000
+
+/**
+ *      t3_cim_ctl_blk_read - read a block from CIM control region
+ *
+ *      @adap: the adapter
+ *      @addr: the start address within the CIM control region
+ *      @n: number of words to read
+ *      @valp: where to store the result
+ *
+ *      Reads a block of 4-byte words from the CIM control region.
+ */
+int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
+                       unsigned int n, unsigned int *valp)
+{
+       int ret = 0;
+
+       if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
+               return -EBUSY;
+
+       for ( ; !ret && n--; addr += 4) {
+               t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr);
+               ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
+                                     0, 5, 2);
+               if (!ret)
+                       *valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA);
+       }
+       return ret;
+}
+
+
+/**
+ *     t3_link_changed - handle interface link changes
+ *     @adapter: the adapter
+ *     @port_id: the port index that changed link state
+ *
+ *     Called when a port's link settings change to propagate the new values
+ *     to the associated PHY and MAC.  After performing the common tasks it
+ *     invokes an OS-specific handler.
+ */
+void t3_link_changed(struct adapter *adapter, int port_id)
+{
+       int link_ok, speed, duplex, fc;
+       struct port_info *pi = adap2pinfo(adapter, port_id);
+       struct cphy *phy = &pi->phy;
+       struct cmac *mac = &pi->mac;
+       struct link_config *lc = &pi->link_config;
+
+       phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
+
+       if (link_ok != lc->link_ok && adapter->params.rev > 0 &&
+           uses_xaui(adapter)) {
+               if (link_ok)
+                       t3b_pcs_reset(mac);
+               t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
+                            link_ok ? F_TXACTENABLE | F_RXEN : 0);
+       }
+       lc->link_ok = link_ok;
+       lc->speed = speed < 0 ? SPEED_INVALID : speed;
+       lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
+       if (lc->requested_fc & PAUSE_AUTONEG)
+               fc &= lc->requested_fc;
+       else
+               fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+
+       if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
+               /* Set MAC speed, duplex, and flow control to match PHY. */
+               t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
+               lc->fc = fc;
+       }
+
+       t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
+}
+
+/**
+ *     t3_link_start - apply link configuration to MAC/PHY
+ *     @phy: the PHY to setup
+ *     @mac: the MAC to setup
+ *     @lc: the requested link configuration
+ *
+ *     Set up a port's MAC and PHY according to a desired link configuration.
+ *     - If the PHY can auto-negotiate first decide what to advertise, then
+ *       enable/disable auto-negotiation as desired, and reset.
+ *     - If the PHY does not auto-negotiate just reset it.
+ *     - If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
+ *       otherwise do it later based on the outcome of auto-negotiation.
+ */
+int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
+{
+       unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
+
+       lc->link_ok = 0;
+       if (lc->supported & SUPPORTED_Autoneg) {
+               lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause);
+               if (fc) {
+                       lc->advertising |= ADVERTISED_Asym_Pause;
+                       if (fc & PAUSE_RX)
+                               lc->advertising |= ADVERTISED_Pause;
+               }
+               phy->ops->advertise(phy, lc->advertising);
+
+               if (lc->autoneg == AUTONEG_DISABLE) {
+                       lc->speed = lc->requested_speed;
+                       lc->duplex = lc->requested_duplex;
+                       lc->fc = (unsigned char)fc;
+                       t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex,
+                                                  fc);
+                       /* Also disables autoneg */
+                       phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
+                       phy->ops->reset(phy, 0);
+               } else
+                       phy->ops->autoneg_enable(phy);
+       } else {
+               t3_mac_set_speed_duplex_fc(mac, -1, -1, fc);
+               lc->fc = (unsigned char)fc;
+               phy->ops->reset(phy, 0);
+       }
+       return 0;
+}
+
+/**
+ *     t3_set_vlan_accel - control HW VLAN extraction
+ *     @adapter: the adapter
+ *     @ports: bitmap of adapter ports to operate on
+ *     @on: enable (1) or disable (0) HW VLAN extraction
+ *
+ *     Enables or disables HW extraction of VLAN tags for the given port.
+ */
+void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on)
+{
+       t3_set_reg_field(adapter, A_TP_OUT_CONFIG,
+                        ports << S_VLANEXTRACTIONENABLE,
+                        on ? (ports << S_VLANEXTRACTIONENABLE) : 0);
+}
+
+struct intr_info {
+       unsigned int mask;      /* bits to check in interrupt status */
+       const char *msg;        /* message to print or NULL */
+       short stat_idx;         /* stat counter to increment or -1 */
+       unsigned short fatal:1; /* whether the condition reported is fatal */
+};
+
+/**
+ *     t3_handle_intr_status - table driven interrupt handler
+ *     @adapter: the adapter that generated the interrupt
+ *     @reg: the interrupt status register to process
+ *     @mask: a mask to apply to the interrupt status
+ *     @acts: table of interrupt actions
+ *     @stats: statistics counters tracking interrupt occurences
+ *
+ *     A table driven interrupt handler that applies a set of masks to an
+ *     interrupt status word and performs the corresponding actions if the
+ *     interrupts described by the mask have occured.  The actions include
+ *     optionally printing a warning or alert message, and optionally
+ *     incrementing a stat counter.  The table is terminated by an entry
+ *     specifying mask 0.  Returns the number of fatal interrupt conditions.
+ */
+static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
+                                unsigned int mask,
+                                const struct intr_info *acts,
+                                unsigned long *stats)
+{
+       int fatal = 0;
+       unsigned int status = t3_read_reg(adapter, reg) & mask;
+
+       for (; acts->mask; ++acts) {
+               if (!(status & acts->mask))
+                       continue;
+               if (acts->fatal) {
+                       fatal++;
+                       CH_ALERT(adapter, "%s (0x%x)\n",
+                                acts->msg, status & acts->mask);
+               } else if (acts->msg)
+                       CH_WARN(adapter, "%s (0x%x)\n",
+                               acts->msg, status & acts->mask);
+               if (acts->stat_idx >= 0)
+                       stats[acts->stat_idx]++;
+       }
+       if (status)             /* clear processed interrupts */
+               t3_write_reg(adapter, reg, status);
+       return fatal;
+}
+
+#define SGE_INTR_MASK (F_RSPQDISABLED)
+#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
+                      F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
+                      F_NFASRCHFAIL)
+#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
+#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
+                      V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
+                      F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW)
+#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
+                       F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
+                       F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
+                       F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \
+                       V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \
+                       V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */)
+#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\
+                       F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \
+                       /* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \
+                       V_BISTERR(M_BISTERR) | F_PEXERR)
+#define ULPRX_INTR_MASK F_PARERR
+#define ULPTX_INTR_MASK 0
+#define CPLSW_INTR_MASK (F_TP_FRAMING_ERROR | \
+                        F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \
+                        F_ZERO_SWITCH_ERROR)
+#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \
+                      F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \
+                      F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \
+                      F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT)
+#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \
+                       V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \
+                       V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR))
+#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \
+                       V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \
+                       V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR))
+#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \
+                      V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \
+                      V_RXTPPARERRENB(M_RXTPPARERRENB) | \
+                      V_MCAPARERRENB(M_MCAPARERRENB))
+#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
+                     F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
+                     F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
+                     F_MPS0 | F_CPL_SWITCH)
+
+/*
+ * Interrupt handler for the PCIX1 module.
+ */
+static void pci_intr_handler(struct adapter *adapter)
+{
+       static const struct intr_info pcix1_intr_info[] = {
+               {F_MSTDETPARERR, "PCI master detected parity error", -1, 1},
+               {F_SIGTARABT, "PCI signaled target abort", -1, 1},
+               {F_RCVTARABT, "PCI received target abort", -1, 1},
+               {F_RCVMSTABT, "PCI received master abort", -1, 1},
+               {F_SIGSYSERR, "PCI signaled system error", -1, 1},
+               {F_DETPARERR, "PCI detected parity error", -1, 1},
+               {F_SPLCMPDIS, "PCI split completion discarded", -1, 1},
+               {F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1},
+               {F_RCVSPLCMPERR, "PCI received split completion error", -1,
+                1},
+               {F_DETCORECCERR, "PCI correctable ECC error",
+                STAT_PCI_CORR_ECC, 0},
+               {F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1},
+               {F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
+               {V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1,
+                1},
+               {V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1,
+                1},
+               {V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1,
+                1},
+               {V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity "
+                "error", -1, 1},
+               {0}
+       };
+
+       if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK,
+                                 pcix1_intr_info, adapter->irq_stats))
+               t3_fatal_err(adapter);
+}
+
+/*
+ * Interrupt handler for the PCIE module.
+ */
+static void pcie_intr_handler(struct adapter *adapter)
+{
+       static const struct intr_info pcie_intr_info[] = {
+               {F_PEXERR, "PCI PEX error", -1, 1},
+               {F_UNXSPLCPLERRR,
+                "PCI unexpected split completion DMA read error", -1, 1},
+               {F_UNXSPLCPLERRC,
+                "PCI unexpected split completion DMA command error", -1, 1},
+               {F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
+               {F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1},
+               {F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1},
+               {F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1},
+               {V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR),
+                "PCI MSI-X table/PBA parity error", -1, 1},
+               {V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1},
+               {0}
+       };
+
+       if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
+                                 pcie_intr_info, adapter->irq_stats))
+               t3_fatal_err(adapter);
+}
+
+/*
+ * TP interrupt handler.
+ */
+static void tp_intr_handler(struct adapter *adapter)
+{
+       static const struct intr_info tp_intr_info[] = {
+               {0xffffff, "TP parity error", -1, 1},
+               {0x1000000, "TP out of Rx pages", -1, 1},
+               {0x2000000, "TP out of Tx pages", -1, 1},
+               {0}
+       };
+
+       if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff,
+                                 tp_intr_info, NULL))
+               t3_fatal_err(adapter);
+}
+
+/*
+ * CIM interrupt handler.
+ */
+static void cim_intr_handler(struct adapter *adapter)
+{
+       static const struct intr_info cim_intr_info[] = {
+               {F_RSVDSPACEINT, "CIM reserved space write", -1, 1},
+               {F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1},
+               {F_FLASHRANGEINT, "CIM flash address out of range", -1, 1},
+               {F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1},
+               {F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1},
+               {F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1},
+               {F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1},
+               {F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1},
+               {F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1},
+               {F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1},
+               {F_BLKRDPLINT, "CIM block read from PL space", -1, 1},
+               {F_BLKWRPLINT, "CIM block write to PL space", -1, 1},
+               {0}
+       };
+
+       if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, 0xffffffff,
+                                 cim_intr_info, NULL))
+               t3_fatal_err(adapter);
+}
+
+/*
+ * ULP RX interrupt handler.
+ */
+static void ulprx_intr_handler(struct adapter *adapter)
+{
+       static const struct intr_info ulprx_intr_info[] = {
+               {F_PARERR, "ULP RX parity error", -1, 1},
+               {0}
+       };
+
+       if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff,
+                                 ulprx_intr_info, NULL))
+               t3_fatal_err(adapter);
+}
+
+/*
+ * ULP TX interrupt handler.
+ */
+static void ulptx_intr_handler(struct adapter *adapter)
+{
+       static const struct intr_info ulptx_intr_info[] = {
+               {F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds",
+                STAT_ULP_CH0_PBL_OOB, 0},
+               {F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds",
+                STAT_ULP_CH1_PBL_OOB, 0},
+               {0}
+       };
+
+       if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff,
+                                 ulptx_intr_info, adapter->irq_stats))
+               t3_fatal_err(adapter);
+}
+
+#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \
+       F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \
+       F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \
+       F_ICSPI1_TX_FRAMING_ERROR)
+#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \
+       F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \
+       F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \
+       F_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
+
+/*
+ * PM TX interrupt handler.
+ */
+static void pmtx_intr_handler(struct adapter *adapter)
+{
+       static const struct intr_info pmtx_intr_info[] = {
+               {F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1},
+               {ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1},
+               {OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1},
+               {V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR),
+                "PMTX ispi parity error", -1, 1},
+               {V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR),
+                "PMTX ospi parity error", -1, 1},
+               {0}
+       };
+
+       if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff,
+                                 pmtx_intr_info, NULL))
+               t3_fatal_err(adapter);
+}
+
+#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \
+       F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \
+       F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \
+       F_IESPI1_TX_FRAMING_ERROR)
+#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \
+       F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \
+       F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \
+       F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
+
+/*
+ * PM RX interrupt handler.
+ */
+static void pmrx_intr_handler(struct adapter *adapter)
+{
+       static const struct intr_info pmrx_intr_info[] = {
+               {F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1},
+               {IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1},
+               {OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1},
+               {V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR),
+                "PMRX ispi parity error", -1, 1},
+               {V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR),
+                "PMRX ospi parity error", -1, 1},
+               {0}
+       };
+
+       if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff,
+                                 pmrx_intr_info, NULL))
+               t3_fatal_err(adapter);
+}
+
+/*
+ * CPL switch interrupt handler.
+ */
+static void cplsw_intr_handler(struct adapter *adapter)
+{
+       static const struct intr_info cplsw_intr_info[] = {
+/*             { F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 }, */
+               {F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1},
+               {F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1},
+               {F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1},
+               {F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1},
+               {0}
+       };
+
+       if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff,
+                                 cplsw_intr_info, NULL))
+               t3_fatal_err(adapter);
+}
+
+/*
+ * MPS interrupt handler.
+ */
+static void mps_intr_handler(struct adapter *adapter)
+{
+       static const struct intr_info mps_intr_info[] = {
+               {0x1ff, "MPS parity error", -1, 1},
+               {0}
+       };
+
+       if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff,
+                                 mps_intr_info, NULL))
+               t3_fatal_err(adapter);
+}
+
+#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE)
+
+/*
+ * MC7 interrupt handler.
+ */
+static void mc7_intr_handler(struct mc7 *mc7)
+{
+       struct adapter *adapter = mc7->adapter;
+       u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE);
+
+       if (cause & F_CE) {
+               mc7->stats.corr_err++;
+               CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, "
+                       "data 0x%x 0x%x 0x%x\n", mc7->name,
+                       t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR),
+                       t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0),
+                       t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1),
+                       t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2));
+       }
+
+       if (cause & F_UE) {
+               mc7->stats.uncorr_err++;
+               CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, "
+                        "data 0x%x 0x%x 0x%x\n", mc7->name,
+                        t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR),
+                        t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0),
+                        t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1),
+                        t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2));
+       }
+
+       if (G_PE(cause)) {
+               mc7->stats.parity_err++;
+               CH_ALERT(adapter, "%s MC7 parity error 0x%x\n",
+                        mc7->name, G_PE(cause));
+       }
+
+       if (cause & F_AE) {
+               u32 addr = 0;
+
+               if (adapter->params.rev > 0)
+                       addr = t3_read_reg(adapter,
+                                          mc7->offset + A_MC7_ERR_ADDR);
+               mc7->stats.addr_err++;
+               CH_ALERT(adapter, "%s MC7 address error: 0x%x\n",
+                        mc7->name, addr);
+       }
+
+       if (cause & MC7_INTR_FATAL)
+               t3_fatal_err(adapter);
+
+       t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause);
+}
+
+#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
+                       V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR))
+/*
+ * XGMAC interrupt handler.
+ */
+static int mac_intr_handler(struct adapter *adap, unsigned int idx)
+{
+       struct cmac *mac = &adap2pinfo(adap, idx)->mac;
+       u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset);
+
+       if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
+               mac->stats.tx_fifo_parity_err++;
+               CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx);
+       }
+       if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) {
+               mac->stats.rx_fifo_parity_err++;
+               CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx);
+       }
+       if (cause & F_TXFIFO_UNDERRUN)
+               mac->stats.tx_fifo_urun++;
+       if (cause & F_RXFIFO_OVERFLOW)
+               mac->stats.rx_fifo_ovfl++;
+       if (cause & V_SERDES_LOS(M_SERDES_LOS))
+               mac->stats.serdes_signal_loss++;
+       if (cause & F_XAUIPCSCTCERR)
+               mac->stats.xaui_pcs_ctc_err++;
+       if (cause & F_XAUIPCSALIGNCHANGE)
+               mac->stats.xaui_pcs_align_change++;
+
+       t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
+       if (cause & XGM_INTR_FATAL)
+               t3_fatal_err(adap);
+       return cause != 0;
+}
+
+/*
+ * Interrupt handler for PHY events.
+ */
+int t3_phy_intr_handler(struct adapter *adapter)
+{
+       static const int intr_gpio_bits[] = { 8, 0x20 };
+
+       u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE);
+
+       for_each_port(adapter, i) {
+               if (cause & intr_gpio_bits[i]) {
+                       struct cphy *phy = &adap2pinfo(adapter, i)->phy;
+                       int phy_cause = phy->ops->intr_handler(phy);
+
+                       if (phy_cause & cphy_cause_link_change)
+                               t3_link_changed(adapter, i);
+                       if (phy_cause & cphy_cause_fifo_error)
+                               phy->fifo_errors++;
+               }
+       }
+
+       t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause);
+       return 0;
+}
+
+/*
+ * T3 slow path (non-data) interrupt handler.
+ */
+int t3_slow_intr_handler(struct adapter *adapter)
+{
+       u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0);
+
+       cause &= adapter->slow_intr_mask;
+       if (!cause)
+               return 0;
+       if (cause & F_PCIM0) {
+               if (is_pcie(adapter))
+                       pcie_intr_handler(adapter);
+               else
+                       pci_intr_handler(adapter);
+       }
+       if (cause & F_SGE3)
+               t3_sge_err_intr_handler(adapter);
+       if (cause & F_MC7_PMRX)
+               mc7_intr_handler(&adapter->pmrx);
+       if (cause & F_MC7_PMTX)
+               mc7_intr_handler(&adapter->pmtx);
+       if (cause & F_MC7_CM)
+               mc7_intr_handler(&adapter->cm);
+       if (cause & F_CIM)
+               cim_intr_handler(adapter);
+       if (cause & F_TP1)
+               tp_intr_handler(adapter);
+       if (cause & F_ULP2_RX)
+               ulprx_intr_handler(adapter);
+       if (cause & F_ULP2_TX)
+               ulptx_intr_handler(adapter);
+       if (cause & F_PM1_RX)
+               pmrx_intr_handler(adapter);
+       if (cause & F_PM1_TX)
+               pmtx_intr_handler(adapter);
+       if (cause & F_CPL_SWITCH)
+               cplsw_intr_handler(adapter);
+       if (cause & F_MPS0)
+               mps_intr_handler(adapter);
+       if (cause & F_MC5A)
+               t3_mc5_intr_handler(&adapter->mc5);
+       if (cause & F_XGMAC0_0)
+               mac_intr_handler(adapter, 0);
+       if (cause & F_XGMAC0_1)
+               mac_intr_handler(adapter, 1);
+       if (cause & F_T3DBG)
+               t3_os_ext_intr_handler(adapter);
+
+       /* Clear the interrupts just processed. */
+       t3_write_reg(adapter, A_PL_INT_CAUSE0, cause);
+       t3_read_reg(adapter, A_PL_INT_CAUSE0);  /* flush */
+       return 1;
+}
+
+/**
+ *     t3_intr_enable - enable interrupts
+ *     @adapter: the adapter whose interrupts should be enabled
+ *
+ *     Enable interrupts by setting the interrupt enable registers of the
+ *     various HW modules and then enabling the top-level interrupt
+ *     concentrator.
+ */
+void t3_intr_enable(struct adapter *adapter)
+{
+       static const struct addr_val_pair intr_en_avp[] = {
+               {A_SG_INT_ENABLE, SGE_INTR_MASK},
+               {A_MC7_INT_ENABLE, MC7_INTR_MASK},
+               {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
+                MC7_INTR_MASK},
+               {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
+                MC7_INTR_MASK},
+               {A_MC5_DB_INT_ENABLE, MC5_INTR_MASK},
+               {A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK},
+               {A_TP_INT_ENABLE, 0x3bfffff},
+               {A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK},
+               {A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK},
+               {A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK},
+               {A_MPS_INT_ENABLE, MPS_INTR_MASK},
+       };
+
+       adapter->slow_intr_mask = PL_INTR_MASK;
+
+       t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0);
+
+       if (adapter->params.rev > 0) {
+               t3_write_reg(adapter, A_CPL_INTR_ENABLE,
+                            CPLSW_INTR_MASK | F_CIM_OVFL_ERROR);
+               t3_write_reg(adapter, A_ULPTX_INT_ENABLE,
+                            ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 |
+                            F_PBL_BOUND_ERR_CH1);
+       } else {
+               t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK);
+               t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK);
+       }
+
+       t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW,
+                    adapter_info(adapter)->gpio_intr);
+       t3_write_reg(adapter, A_T3DBG_INT_ENABLE,
+                    adapter_info(adapter)->gpio_intr);
+       if (is_pcie(adapter))
+               t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK);
+       else
+               t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK);
+       t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask);
+       t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */
+}
+
+/**
+ *     t3_intr_disable - disable a card's interrupts
+ *     @adapter: the adapter whose interrupts should be disabled
+ *
+ *     Disable interrupts.  We only disable the top-level interrupt
+ *     concentrator and the SGE data interrupts.
+ */
+void t3_intr_disable(struct adapter *adapter)
+{
+       t3_write_reg(adapter, A_PL_INT_ENABLE0, 0);
+       t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */
+       adapter->slow_intr_mask = 0;
+}
+
+/**
+ *     t3_intr_clear - clear all interrupts
+ *     @adapter: the adapter whose interrupts should be cleared
+ *
+ *     Clears all interrupts.
+ */
+void t3_intr_clear(struct adapter *adapter)
+{
+       static const unsigned int cause_reg_addr[] = {
+               A_SG_INT_CAUSE,
+               A_SG_RSPQ_FL_STATUS,
+               A_PCIX_INT_CAUSE,
+               A_MC7_INT_CAUSE,
+               A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
+               A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
+               A_CIM_HOST_INT_CAUSE,
+               A_TP_INT_CAUSE,
+               A_MC5_DB_INT_CAUSE,
+               A_ULPRX_INT_CAUSE,
+               A_ULPTX_INT_CAUSE,
+               A_CPL_INTR_CAUSE,
+               A_PM1_TX_INT_CAUSE,
+               A_PM1_RX_INT_CAUSE,
+               A_MPS_INT_CAUSE,
+               A_T3DBG_INT_CAUSE,
+       };
+       unsigned int i;
+
+       /* Clear PHY and MAC interrupts for each port. */
+       for_each_port(adapter, i)
+           t3_port_intr_clear(adapter, i);
+
+       for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
+               t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
+
+       t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
+       t3_read_reg(adapter, A_PL_INT_CAUSE0);  /* flush */
+}
+
+/**
+ *     t3_port_intr_enable - enable port-specific interrupts
+ *     @adapter: associated adapter
+ *     @idx: index of port whose interrupts should be enabled
+ *
+ *     Enable port-specific (i.e., MAC and PHY) interrupts for the given
+ *     adapter port.
+ */
+void t3_port_intr_enable(struct adapter *adapter, int idx)
+{
+       struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+       t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), XGM_INTR_MASK);
+       t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
+       phy->ops->intr_enable(phy);
+}
+
+/**
+ *     t3_port_intr_disable - disable port-specific interrupts
+ *     @adapter: associated adapter
+ *     @idx: index of port whose interrupts should be disabled
+ *
+ *     Disable port-specific (i.e., MAC and PHY) interrupts for the given
+ *     adapter port.
+ */
+void t3_port_intr_disable(struct adapter *adapter, int idx)
+{
+       struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+       t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), 0);
+       t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
+       phy->ops->intr_disable(phy);
+}
+
+/**
+ *     t3_port_intr_clear - clear port-specific interrupts
+ *     @adapter: associated adapter
+ *     @idx: index of port whose interrupts to clear
+ *
+ *     Clear port-specific (i.e., MAC and PHY) interrupts for the given
+ *     adapter port.
+ */
+void t3_port_intr_clear(struct adapter *adapter, int idx)
+{
+       struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
+
+       t3_write_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx), 0xffffffff);
+       t3_read_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx)); /* flush */
+       phy->ops->intr_clear(phy);
+}
+
+/**
+ *     t3_sge_write_context - write an SGE context
+ *     @adapter: the adapter
+ *     @id: the context id
+ *     @type: the context type
+ *
+ *     Program an SGE context with the values already loaded in the
+ *     CONTEXT_DATA? registers.
+ */
+static int t3_sge_write_context(struct adapter *adapter, unsigned int id,
+                               unsigned int type)
+{
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff);
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
+       t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+                    V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
+       return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+                              0, 5, 1);
+}
+
+/**
+ *     t3_sge_init_ecntxt - initialize an SGE egress context
+ *     @adapter: the adapter to configure
+ *     @id: the context id
+ *     @gts_enable: whether to enable GTS for the context
+ *     @type: the egress context type
+ *     @respq: associated response queue
+ *     @base_addr: base address of queue
+ *     @size: number of queue entries
+ *     @token: uP token
+ *     @gen: initial generation value for the context
+ *     @cidx: consumer pointer
+ *
+ *     Initialize an SGE egress context and make it ready for use.  If the
+ *     platform allows concurrent context operations, the caller is
+ *     responsible for appropriate locking.
+ */
+int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable,
+                      enum sge_context_type type, int respq, u64 base_addr,
+                      unsigned int size, unsigned int token, int gen,
+                      unsigned int cidx)
+{
+       unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM;
+
+       if (base_addr & 0xfff)  /* must be 4K aligned */
+               return -EINVAL;
+       if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+               return -EBUSY;
+
+       base_addr >>= 12;
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) |
+                    V_EC_CREDITS(credits) | V_EC_GTS(gts_enable));
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) |
+                    V_EC_BASE_LO(base_addr & 0xffff));
+       base_addr >>= 16;
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA2, base_addr);
+       base_addr >>= 32;
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
+                    V_EC_BASE_HI(base_addr & 0xf) | V_EC_RESPQ(respq) |
+                    V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) |
+                    F_EC_VALID);
+       return t3_sge_write_context(adapter, id, F_EGRESS);
+}
+
+/**
+ *     t3_sge_init_flcntxt - initialize an SGE free-buffer list context
+ *     @adapter: the adapter to configure
+ *     @id: the context id
+ *     @gts_enable: whether to enable GTS for the context
+ *     @base_addr: base address of queue
+ *     @size: number of queue entries
+ *     @bsize: size of each buffer for this queue
+ *     @cong_thres: threshold to signal congestion to upstream producers
+ *     @gen: initial generation value for the context
+ *     @cidx: consumer pointer
+ *
+ *     Initialize an SGE free list context and make it ready for use.  The
+ *     caller is responsible for ensuring only one context operation occurs
+ *     at a time.
+ */
+int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id,
+                       int gts_enable, u64 base_addr, unsigned int size,
+                       unsigned int bsize, unsigned int cong_thres, int gen,
+                       unsigned int cidx)
+{
+       if (base_addr & 0xfff)  /* must be 4K aligned */
+               return -EINVAL;
+       if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+               return -EBUSY;
+
+       base_addr >>= 12;
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA0, base_addr);
+       base_addr >>= 32;
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA1,
+                    V_FL_BASE_HI((u32) base_addr) |
+                    V_FL_INDEX_LO(cidx & M_FL_INDEX_LO));
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) |
+                    V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) |
+                    V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO));
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
+                    V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) |
+                    V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable));
+       return t3_sge_write_context(adapter, id, F_FREELIST);
+}
+
+/**
+ *     t3_sge_init_rspcntxt - initialize an SGE response queue context
+ *     @adapter: the adapter to configure
+ *     @id: the context id
+ *     @irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ
+ *     @base_addr: base address of queue
+ *     @size: number of queue entries
+ *     @fl_thres: threshold for selecting the normal or jumbo free list
+ *     @gen: initial generation value for the context
+ *     @cidx: consumer pointer
+ *
+ *     Initialize an SGE response queue context and make it ready for use.
+ *     The caller is responsible for ensuring only one context operation
+ *     occurs at a time.
+ */
+int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id,
+                        int irq_vec_idx, u64 base_addr, unsigned int size,
+                        unsigned int fl_thres, int gen, unsigned int cidx)
+{
+       unsigned int intr = 0;
+
+       if (base_addr & 0xfff)  /* must be 4K aligned */
+               return -EINVAL;
+       if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+               return -EBUSY;
+
+       base_addr >>= 12;
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) |
+                    V_CQ_INDEX(cidx));
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
+       base_addr >>= 32;
+       if (irq_vec_idx >= 0)
+               intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN;
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
+                    V_CQ_BASE_HI((u32) base_addr) | intr | V_RQ_GEN(gen));
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres);
+       return t3_sge_write_context(adapter, id, F_RESPONSEQ);
+}
+
+/**
+ *     t3_sge_init_cqcntxt - initialize an SGE completion queue context
+ *     @adapter: the adapter to configure
+ *     @id: the context id
+ *     @base_addr: base address of queue
+ *     @size: number of queue entries
+ *     @rspq: response queue for async notifications
+ *     @ovfl_mode: CQ overflow mode
+ *     @credits: completion queue credits
+ *     @credit_thres: the credit threshold
+ *
+ *     Initialize an SGE completion queue context and make it ready for use.
+ *     The caller is responsible for ensuring only one context operation
+ *     occurs at a time.
+ */
+int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
+                       unsigned int size, int rspq, int ovfl_mode,
+                       unsigned int credits, unsigned int credit_thres)
+{
+       if (base_addr & 0xfff)  /* must be 4K aligned */
+               return -EINVAL;
+       if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+               return -EBUSY;
+
+       base_addr >>= 12;
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size));
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
+       base_addr >>= 32;
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
+                    V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) |
+                    V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode));
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
+                    V_CQ_CREDIT_THRES(credit_thres));
+       return t3_sge_write_context(adapter, id, F_CQ);
+}
+
+/**
+ *     t3_sge_enable_ecntxt - enable/disable an SGE egress context
+ *     @adapter: the adapter
+ *     @id: the egress context id
+ *     @enable: enable (1) or disable (0) the context
+ *
+ *     Enable or disable an SGE egress context.  The caller is responsible for
+ *     ensuring only one context operation occurs at a time.
+ */
+int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable)
+{
+       if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+               return -EBUSY;
+
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID);
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable));
+       t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+                    V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
+       return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+                              0, 5, 1);
+}
+
+/**
+ *     t3_sge_disable_fl - disable an SGE free-buffer list
+ *     @adapter: the adapter
+ *     @id: the free list context id
+ *
+ *     Disable an SGE free-buffer list.  The caller is responsible for
+ *     ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_fl(struct adapter *adapter, unsigned int id)
+{
+       if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+               return -EBUSY;
+
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE));
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+                    V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
+       return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+                              0, 5, 1);
+}
+
+/**
+ *     t3_sge_disable_rspcntxt - disable an SGE response queue
+ *     @adapter: the adapter
+ *     @id: the response queue context id
+ *
+ *     Disable an SGE response queue.  The caller is responsible for
+ *     ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id)
+{
+       if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+               return -EBUSY;
+
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+                    V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
+       return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+                              0, 5, 1);
+}
+
+/**
+ *     t3_sge_disable_cqcntxt - disable an SGE completion queue
+ *     @adapter: the adapter
+ *     @id: the completion queue context id
+ *
+ *     Disable an SGE completion queue.  The caller is responsible for
+ *     ensuring only one context operation occurs at a time.
+ */
+int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id)
+{
+       if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+               return -EBUSY;
+
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
+       t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+                    V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
+       return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+                              0, 5, 1);
+}
+
+/**
+ *     t3_sge_cqcntxt_op - perform an operation on a completion queue context
+ *     @adapter: the adapter
+ *     @id: the context id
+ *     @op: the operation to perform
+ *
+ *     Perform the selected operation on an SGE completion queue context.
+ *     The caller is responsible for ensuring only one context operation
+ *     occurs at a time.
+ */
+int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
+                     unsigned int credits)
+{
+       u32 val;
+
+       if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+               return -EBUSY;
+
+       t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16);
+       t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
+                    V_CONTEXT(id) | F_CQ);
+       if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
+                               0, 5, 1, &val))
+               return -EIO;
+
+       if (op >= 2 && op < 7) {
+               if (adapter->params.rev > 0)
+                       return G_CQ_INDEX(val);
+
+               t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+                            V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
+               if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
+                                   F_CONTEXT_CMD_BUSY, 0, 5, 1))
+                       return -EIO;
+               return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
+       }
+       return 0;
+}
+
+/**
+ *     t3_sge_read_context - read an SGE context
+ *     @type: the context type
+ *     @adapter: the adapter
+ *     @id: the context id
+ *     @data: holds the retrieved context
+ *
+ *     Read an SGE egress context.  The caller is responsible for ensuring
+ *     only one context operation occurs at a time.
+ */
+static int t3_sge_read_context(unsigned int type, struct adapter *adapter,
+                              unsigned int id, u32 data[4])
+{
+       if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
+               return -EBUSY;
+
+       t3_write_reg(adapter, A_SG_CONTEXT_CMD,
+                    V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id));
+       if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0,
+                           5, 1))
+               return -EIO;
+       data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0);
+       data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1);
+       data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2);
+       data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3);
+       return 0;
+}
+
+/**
+ *     t3_sge_read_ecntxt - read an SGE egress context
+ *     @adapter: the adapter
+ *     @id: the context id
+ *     @data: holds the retrieved context
+ *
+ *     Read an SGE egress context.  The caller is responsible for ensuring
+ *     only one context operation occurs at a time.
+ */
+int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+       if (id >= 65536)
+               return -EINVAL;
+       return t3_sge_read_context(F_EGRESS, adapter, id, data);
+}
+
+/**
+ *     t3_sge_read_cq - read an SGE CQ context
+ *     @adapter: the adapter
+ *     @id: the context id
+ *     @data: holds the retrieved context
+ *
+ *     Read an SGE CQ context.  The caller is responsible for ensuring
+ *     only one context operation occurs at a time.
+ */
+int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+       if (id >= 65536)
+               return -EINVAL;
+       return t3_sge_read_context(F_CQ, adapter, id, data);
+}
+
+/**
+ *     t3_sge_read_fl - read an SGE free-list context
+ *     @adapter: the adapter
+ *     @id: the context id
+ *     @data: holds the retrieved context
+ *
+ *     Read an SGE free-list context.  The caller is responsible for ensuring
+ *     only one context operation occurs at a time.
+ */
+int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+       if (id >= SGE_QSETS * 2)
+               return -EINVAL;
+       return t3_sge_read_context(F_FREELIST, adapter, id, data);
+}
+
+/**
+ *     t3_sge_read_rspq - read an SGE response queue context
+ *     @adapter: the adapter
+ *     @id: the context id
+ *     @data: holds the retrieved context
+ *
+ *     Read an SGE response queue context.  The caller is responsible for
+ *     ensuring only one context operation occurs at a time.
+ */
+int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4])
+{
+       if (id >= SGE_QSETS)
+               return -EINVAL;
+       return t3_sge_read_context(F_RESPONSEQ, adapter, id, data);
+}
+
+/**
+ *     t3_config_rss - configure Rx packet steering
+ *     @adapter: the adapter
+ *     @rss_config: RSS settings (written to TP_RSS_CONFIG)
+ *     @cpus: values for the CPU lookup table (0xff terminated)
+ *     @rspq: values for the response queue lookup table (0xffff terminated)
+ *
+ *     Programs the receive packet steering logic.  @cpus and @rspq provide
+ *     the values for the CPU and response queue lookup tables.  If they
+ *     provide fewer values than the size of the tables the supplied values
+ *     are used repeatedly until the tables are fully populated.
+ */
+void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
+                  const u8 * cpus, const u16 *rspq)
+{
+       int i, j, cpu_idx = 0, q_idx = 0;
+
+       if (cpus)
+               for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+                       u32 val = i << 16;
+
+                       for (j = 0; j < 2; ++j) {
+                               val |= (cpus[cpu_idx++] & 0x3f) << (8 * j);
+                               if (cpus[cpu_idx] == 0xff)
+                                       cpu_idx = 0;
+                       }
+                       t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val);
+               }
+
+       if (rspq)
+               for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+                       t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
+                                    (i << 16) | rspq[q_idx++]);
+                       if (rspq[q_idx] == 0xffff)
+                               q_idx = 0;
+               }
+
+       t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config);
+}
+
+/**
+ *     t3_read_rss - read the contents of the RSS tables
+ *     @adapter: the adapter
+ *     @lkup: holds the contents of the RSS lookup table
+ *     @map: holds the contents of the RSS map table
+ *
+ *     Reads the contents of the receive packet steering tables.
+ */
+int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map)
+{
+       int i;
+       u32 val;
+
+       if (lkup)
+               for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+                       t3_write_reg(adapter, A_TP_RSS_LKP_TABLE,
+                                    0xffff0000 | i);
+                       val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE);
+                       if (!(val & 0x80000000))
+                               return -EAGAIN;
+                       *lkup++ = val;
+                       *lkup++ = (val >> 8);
+               }
+
+       if (map)
+               for (i = 0; i < RSS_TABLE_SIZE; ++i) {
+                       t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
+                                    0xffff0000 | i);
+                       val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE);
+                       if (!(val & 0x80000000))
+                               return -EAGAIN;
+                       *map++ = val;
+               }
+       return 0;
+}
+
+/**
+ *     t3_tp_set_offload_mode - put TP in NIC/offload mode
+ *     @adap: the adapter
+ *     @enable: 1 to select offload mode, 0 for regular NIC
+ *
+ *     Switches TP to NIC/offload mode.
+ */
+void t3_tp_set_offload_mode(struct adapter *adap, int enable)
+{
+       if (is_offload(adap) || !enable)
+               t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE,
+                                V_NICMODE(!enable));
+}
+
+/**
+ *     pm_num_pages - calculate the number of pages of the payload memory
+ *     @mem_size: the size of the payload memory
+ *     @pg_size: the size of each payload memory page
+ *
+ *     Calculate the number of pages, each of the given size, that fit in a
+ *     memory of the specified size, respecting the HW requirement that the
+ *     number of pages must be a multiple of 24.
+ */
+static inline unsigned int pm_num_pages(unsigned int mem_size,
+                                       unsigned int pg_size)
+{
+       unsigned int n = mem_size / pg_size;
+
+       return n - n % 24;
+}
+
+#define mem_region(adap, start, size, reg) \
+       t3_write_reg((adap), A_ ## reg, (start)); \
+       start += size
+
+/*
+ *     partition_mem - partition memory and configure TP memory settings
+ *     @adap: the adapter
+ *     @p: the TP parameters
+ *
+ *     Partitions context and payload memory and configures TP's memory
+ *     registers.
+ */
+static void partition_mem(struct adapter *adap, const struct tp_params *p)
+{
+       unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5);
+       unsigned int timers = 0, timers_shift = 22;
+
+       if (adap->params.rev > 0) {
+               if (tids <= 16 * 1024) {
+                       timers = 1;
+                       timers_shift = 16;
+               } else if (tids <= 64 * 1024) {
+                       timers = 2;
+                       timers_shift = 18;
+               } else if (tids <= 256 * 1024) {
+                       timers = 3;
+                       timers_shift = 20;
+               }
+       }
+
+       t3_write_reg(adap, A_TP_PMM_SIZE,
+                    p->chan_rx_size | (p->chan_tx_size >> 16));
+
+       t3_write_reg(adap, A_TP_PMM_TX_BASE, 0);
+       t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size);
+       t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs);
+       t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX),
+                        V_TXDATAACKIDX(fls(p->tx_pg_size) - 12));
+
+       t3_write_reg(adap, A_TP_PMM_RX_BASE, 0);
+       t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size);
+       t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs);
+
+       pstructs = p->rx_num_pgs + p->tx_num_pgs;
+       /* Add a bit of headroom and make multiple of 24 */
+       pstructs += 48;
+       pstructs -= pstructs % 24;
+       t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs);
+
+       m = tids * TCB_SIZE;
+       mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR);
+       mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR);
+       t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m);
+       m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22);
+       mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE);
+       mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE);
+       mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE);
+       mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE);
+
+       m = (m + 4095) & ~0xfff;
+       t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m);
+       t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m);
+
+       tids = (p->cm_size - m - (3 << 20)) / 3072 - 32;
+       m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
+           adap->params.mc5.nfilters - adap->params.mc5.nroutes;
+       if (tids < m)
+               adap->params.mc5.nservers += m - tids;
+}
+
+static inline void tp_wr_indirect(struct adapter *adap, unsigned int addr,
+                                 u32 val)
+{
+       t3_write_reg(adap, A_TP_PIO_ADDR, addr);
+       t3_write_reg(adap, A_TP_PIO_DATA, val);
+}
+
+static void tp_config(struct adapter *adap, const struct tp_params *p)
+{
+       t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU |
+                    F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD |
+                    F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
+       t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
+                    F_MTUENABLE | V_WINDOWSCALEMODE(1) |
+                    V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1));
+       t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
+                    V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
+                    V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) |
+                    F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1));
+       t3_set_reg_field(adap, A_TP_IN_CONFIG, F_IPV6ENABLE | F_NICMODE,
+                        F_IPV6ENABLE | F_NICMODE);
+       t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
+       t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
+       t3_set_reg_field(adap, A_TP_PARA_REG6,
+                        adap->params.rev > 0 ? F_ENABLEESND : F_T3A_ENABLEESND,
+                        0);
+
+       t3_set_reg_field(adap, A_TP_PC_CONFIG,
+                        F_ENABLEEPCMDAFULL | F_ENABLEOCSPIFULL,
+                        F_TXDEFERENABLE | F_HEARBEATDACK | F_TXCONGESTIONMODE |
+                        F_RXCONGESTIONMODE);
+       t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL, 0);
+
+       if (adap->params.rev > 0) {
+               tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
+               t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO,
+                                F_TXPACEAUTO);
+               t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID);
+               t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEAUTOSTRICT);
+       } else
+               t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
+
+       t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0x12121212);
+       t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0x12121212);
+       t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0x1212);
+}
+
+/* Desired TP timer resolution in usec */
+#define TP_TMR_RES 50
+
+/* TCP timer values in ms */
+#define TP_DACK_TIMER 50
+#define TP_RTO_MIN    250
+
+/**
+ *     tp_set_timers - set TP timing parameters
+ *     @adap: the adapter to set
+ *     @core_clk: the core clock frequency in Hz
+ *
+ *     Set TP's timing parameters, such as the various timer resolutions and
+ *     the TCP timer values.
+ */
+static void tp_set_timers(struct adapter *adap, unsigned int core_clk)
+{
+       unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1;
+       unsigned int dack_re = fls(core_clk / 5000) - 1;        /* 200us */
+       unsigned int tstamp_re = fls(core_clk / 1000);  /* 1ms, at least */
+       unsigned int tps = core_clk >> tre;
+
+       t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) |
+                    V_DELAYEDACKRESOLUTION(dack_re) |
+                    V_TIMESTAMPRESOLUTION(tstamp_re));
+       t3_write_reg(adap, A_TP_DACK_TIMER,
+                    (core_clk >> dack_re) / (1000 / TP_DACK_TIMER));
+       t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100);
+       t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504);
+       t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908);
+       t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c);
+       t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) |
+                    V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) |
+                    V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
+                    V_KEEPALIVEMAX(9));
+
+#define SECONDS * tps
+
+       t3_write_reg(adap, A_TP_MSL, adap->params.rev > 0 ? 0 : 2 SECONDS);
+       t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN));
+       t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS);
+       t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS);
+       t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS);
+       t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS);
+       t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS);
+       t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS);
+       t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS);
+
+#undef SECONDS
+}
+
+/**
+ *     t3_tp_set_coalescing_size - set receive coalescing size
+ *     @adap: the adapter
+ *     @size: the receive coalescing size
+ *     @psh: whether a set PSH bit should deliver coalesced data
+ *
+ *     Set the receive coalescing size and PSH bit handling.
+ */
+int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh)
+{
+       u32 val;
+
+       if (size > MAX_RX_COALESCING_LEN)
+               return -EINVAL;
+
+       val = t3_read_reg(adap, A_TP_PARA_REG3);
+       val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN);
+
+       if (size) {
+               val |= F_RXCOALESCEENABLE;
+               if (psh)
+                       val |= F_RXCOALESCEPSHEN;
+               t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
+                            V_MAXRXDATA(MAX_RX_COALESCING_LEN));
+       }
+       t3_write_reg(adap, A_TP_PARA_REG3, val);
+       return 0;
+}
+
+/**
+ *     t3_tp_set_max_rxsize - set the max receive size
+ *     @adap: the adapter
+ *     @size: the max receive size
+ *
+ *     Set TP's max receive size.  This is the limit that applies when
+ *     receive coalescing is disabled.
+ */
+void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size)
+{
+       t3_write_reg(adap, A_TP_PARA_REG7,
+                    V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
+}
+
+static void __devinit init_mtus(unsigned short mtus[])
+{
+       /*
+        * See draft-mathis-plpmtud-00.txt for the values.  The min is 88 so
+        * it can accomodate max size TCP/IP headers when SACK and timestamps
+        * are enabled and still have at least 8 bytes of payload.
+        */
+       mtus[0] = 88;
+       mtus[1] = 256;
+       mtus[2] = 512;
+       mtus[3] = 576;
+       mtus[4] = 808;
+       mtus[5] = 1024;
+       mtus[6] = 1280;
+       mtus[7] = 1492;
+       mtus[8] = 1500;
+       mtus[9] = 2002;
+       mtus[10] = 2048;
+       mtus[11] = 4096;
+       mtus[12] = 4352;
+       mtus[13] = 8192;
+       mtus[14] = 9000;
+       mtus[15] = 9600;
+}
+
+/*
+ * Initial congestion control parameters.
+ */
+static void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
+{
+       a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
+       a[9] = 2;
+       a[10] = 3;
+       a[11] = 4;
+       a[12] = 5;
+       a[13] = 6;
+       a[14] = 7;
+       a[15] = 8;
+       a[16] = 9;
+       a[17] = 10;
+       a[18] = 14;
+       a[19] = 17;
+       a[20] = 21;
+       a[21] = 25;
+       a[22] = 30;
+       a[23] = 35;
+       a[24] = 45;
+       a[25] = 60;
+       a[26] = 80;
+       a[27] = 100;
+       a[28] = 200;
+       a[29] = 300;
+       a[30] = 400;
+       a[31] = 500;
+
+       b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
+       b[9] = b[10] = 1;
+       b[11] = b[12] = 2;
+       b[13] = b[14] = b[15] = b[16] = 3;
+       b[17] = b[18] = b[19] = b[20] = b[21] = 4;
+       b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
+       b[28] = b[29] = 6;
+       b[30] = b[31] = 7;
+}
+
+/* The minimum additive increment value for the congestion control table */
+#define CC_MIN_INCR 2U
+
+/**
+ *     t3_load_mtus - write the MTU and congestion control HW tables
+ *     @adap: the adapter
+ *     @mtus: the unrestricted values for the MTU table
+ *     @alphs: the values for the congestion control alpha parameter
+ *     @beta: the values for the congestion control beta parameter
+ *     @mtu_cap: the maximum permitted effective MTU
+ *
+ *     Write the MTU table with the supplied MTUs capping each at &mtu_cap.
+ *     Update the high-speed congestion control table with the supplied alpha,
+ *     beta, and MTUs.
+ */
+void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
+                 unsigned short alpha[NCCTRL_WIN],
+                 unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap)
+{
+       static const unsigned int avg_pkts[NCCTRL_WIN] = {
+               2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
+               896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
+               28672, 40960, 57344, 81920, 114688, 163840, 229376
+       };
+
+       unsigned int i, w;
+
+       for (i = 0; i < NMTUS; ++i) {
+               unsigned int mtu = min(mtus[i], mtu_cap);
+               unsigned int log2 = fls(mtu);
+
+               if (!(mtu & ((1 << log2) >> 2)))        /* round */
+                       log2--;
+               t3_write_reg(adap, A_TP_MTU_TABLE,
+                            (i << 24) | (log2 << 16) | mtu);
+
+               for (w = 0; w < NCCTRL_WIN; ++w) {
+                       unsigned int inc;
+
+                       inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
+                                 CC_MIN_INCR);
+
+                       t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
+                                    (w << 16) | (beta[w] << 13) | inc);
+               }
+       }
+}
+
+/**
+ *     t3_read_hw_mtus - returns the values in the HW MTU table
+ *     @adap: the adapter
+ *     @mtus: where to store the HW MTU values
+ *
+ *     Reads the HW MTU table.
+ */
+void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS])
+{
+       int i;
+
+       for (i = 0; i < NMTUS; ++i) {
+               unsigned int val;
+
+               t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i);
+               val = t3_read_reg(adap, A_TP_MTU_TABLE);
+               mtus[i] = val & 0x3fff;
+       }
+}
+
+/**
+ *     t3_get_cong_cntl_tab - reads the congestion control table
+ *     @adap: the adapter
+ *     @incr: where to store the alpha values
+ *
+ *     Reads the additive increments programmed into the HW congestion
+ *     control table.
+ */
+void t3_get_cong_cntl_tab(struct adapter *adap,
+                         unsigned short incr[NMTUS][NCCTRL_WIN])
+{
+       unsigned int mtu, w;
+
+       for (mtu = 0; mtu < NMTUS; ++mtu)
+               for (w = 0; w < NCCTRL_WIN; ++w) {
+                       t3_write_reg(adap, A_TP_CCTRL_TABLE,
+                                    0xffff0000 | (mtu << 5) | w);
+                       incr[mtu][w] = t3_read_reg(adap, A_TP_CCTRL_TABLE) &
+                                      0x1fff;
+               }
+}
+
+/**
+ *     t3_tp_get_mib_stats - read TP's MIB counters
+ *     @adap: the adapter
+ *     @tps: holds the returned counter values
+ *
+ *     Returns the values of TP's MIB counters.
+ */
+void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps)
+{
+       t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *) tps,
+                        sizeof(*tps) / sizeof(u32), 0);
+}
+
+#define ulp_region(adap, name, start, len) \
+       t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \
+       t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \
+                    (start) + (len) - 1); \
+       start += len
+
+#define ulptx_region(adap, name, start, len) \
+       t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \
+       t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \
+                    (start) + (len) - 1)
+
+static void ulp_config(struct adapter *adap, const struct tp_params *p)
+{
+       unsigned int m = p->chan_rx_size;
+
+       ulp_region(adap, ISCSI, m, p->chan_rx_size / 8);
+       ulp_region(adap, TDDP, m, p->chan_rx_size / 8);
+       ulptx_region(adap, TPT, m, p->chan_rx_size / 4);
+       ulp_region(adap, STAG, m, p->chan_rx_size / 4);
+       ulp_region(adap, RQ, m, p->chan_rx_size / 4);
+       ulptx_region(adap, PBL, m, p->chan_rx_size / 4);
+       ulp_region(adap, PBL, m, p->chan_rx_size / 4);
+       t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
+}
+
+void t3_config_trace_filter(struct adapter *adapter,
+                           const struct trace_params *tp, int filter_index,
+                           int invert, int enable)
+{
+       u32 addr, key[4], mask[4];
+
+       key[0] = tp->sport | (tp->sip << 16);
+       key[1] = (tp->sip >> 16) | (tp->dport << 16);
+       key[2] = tp->dip;
+       key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20);
+
+       mask[0] = tp->sport_mask | (tp->sip_mask << 16);
+       mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16);
+       mask[2] = tp->dip_mask;
+       mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20);
+
+       if (invert)
+               key[3] |= (1 << 29);
+       if (enable)
+               key[3] |= (1 << 28);
+
+       addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0;
+       tp_wr_indirect(adapter, addr++, key[0]);
+       tp_wr_indirect(adapter, addr++, mask[0]);
+       tp_wr_indirect(adapter, addr++, key[1]);
+       tp_wr_indirect(adapter, addr++, mask[1]);
+       tp_wr_indirect(adapter, addr++, key[2]);
+       tp_wr_indirect(adapter, addr++, mask[2]);
+       tp_wr_indirect(adapter, addr++, key[3]);
+       tp_wr_indirect(adapter, addr, mask[3]);
+       t3_read_reg(adapter, A_TP_PIO_DATA);
+}
+
+/**
+ *     t3_config_sched - configure a HW traffic scheduler
+ *     @adap: the adapter
+ *     @kbps: target rate in Kbps
+ *     @sched: the scheduler index
+ *
+ *     Configure a HW scheduler for the target rate
+ */
+int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched)
+{
+       unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
+       unsigned int clk = adap->params.vpd.cclk * 1000;
+       unsigned int selected_cpt = 0, selected_bpt = 0;
+
+       if (kbps > 0) {
+               kbps *= 125;    /* -> bytes */
+               for (cpt = 1; cpt <= 255; cpt++) {
+                       tps = clk / cpt;
+                       bpt = (kbps + tps / 2) / tps;
+                       if (bpt > 0 && bpt <= 255) {
+                               v = bpt * tps;
+                               delta = v >= kbps ? v - kbps : kbps - v;
+                               if (delta <= mindelta) {
+                                       mindelta = delta;
+                                       selected_cpt = cpt;
+                                       selected_bpt = bpt;
+                               }
+                       } else if (selected_cpt)
+                               break;
+               }
+               if (!selected_cpt)
+                       return -EINVAL;
+       }
+       t3_write_reg(adap, A_TP_TM_PIO_ADDR,
+                    A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
+       v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
+       if (sched & 1)
+               v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
+       else
+               v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
+       t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
+       return 0;
+}
+
+static int tp_init(struct adapter *adap, const struct tp_params *p)
+{
+       int busy = 0;
+
+       tp_config(adap, p);
+       t3_set_vlan_accel(adap, 3, 0);
+
+       if (is_offload(adap)) {
+               tp_set_timers(adap, adap->params.vpd.cclk * 1000);
+               t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE);
+               busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE,
+                                      0, 1000, 5);
+               if (busy)
+                       CH_ERR(adap, "TP initialization timed out\n");
+       }
+
+       if (!busy)
+               t3_write_reg(adap, A_TP_RESET, F_TPRESET);
+       return busy;
+}
+
+int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask)
+{
+       if (port_mask & ~((1 << adap->params.nports) - 1))
+               return -EINVAL;
+       t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
+                        port_mask << S_PORT0ACTIVE);
+       return 0;
+}
+
+/*
+ * Perform the bits of HW initialization that are dependent on the number
+ * of available ports.
+ */
+static void init_hw_for_avail_ports(struct adapter *adap, int nports)
+{
+       int i;
+
+       if (nports == 1) {
+               t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0);
+               t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
+               t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_TPTXPORT0EN |
+                            F_PORT0ACTIVE | F_ENFORCEPKT);
+               t3_write_reg(adap, A_PM1_TX_CFG, 0xc000c000);
+       } else {
+               t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
+               t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
+               t3_write_reg(adap, A_ULPTX_DMA_WEIGHT,
+                            V_D1_WEIGHT(16) | V_D0_WEIGHT(16));
+               t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN |
+                            F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE |
+                            F_ENFORCEPKT);
+               t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000);
+               t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE);
+               t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
+                            V_TX_MOD_QUEUE_REQ_MAP(0xaa));
+               for (i = 0; i < 16; i++)
+                       t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE,
+                                    (i << 16) | 0x1010);
+       }
+}
+
+static int calibrate_xgm(struct adapter *adapter)
+{
+       if (uses_xaui(adapter)) {
+               unsigned int v, i;
+
+               for (i = 0; i < 5; ++i) {
+                       t3_write_reg(adapter, A_XGM_XAUI_IMP, 0);
+                       t3_read_reg(adapter, A_XGM_XAUI_IMP);
+                       msleep(1);
+                       v = t3_read_reg(adapter, A_XGM_XAUI_IMP);
+                       if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) {
+                               t3_write_reg(adapter, A_XGM_XAUI_IMP,
+                                            V_XAUIIMP(G_CALIMP(v) >> 2));
+                               return 0;
+                       }
+               }
+               CH_ERR(adapter, "MAC calibration failed\n");
+               return -1;
+       } else {
+               t3_write_reg(adapter, A_XGM_RGMII_IMP,
+                            V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
+               t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
+                                F_XGM_IMPSETUPDATE);
+       }
+       return 0;
+}
+
+static void calibrate_xgm_t3b(struct adapter *adapter)
+{
+       if (!uses_xaui(adapter)) {
+               t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET |
+                            F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
+               t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0);
+               t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0,
+                                F_XGM_IMPSETUPDATE);
+               t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
+                                0);
+               t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0);
+               t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE);
+       }
+}
+
+struct mc7_timing_params {
+       unsigned char ActToPreDly;
+       unsigned char ActToRdWrDly;
+       unsigned char PreCyc;
+       unsigned char RefCyc[5];
+       unsigned char BkCyc;
+       unsigned char WrToRdDly;
+       unsigned char RdToWrDly;
+};
+
+/*
+ * Write a value to a register and check that the write completed.  These
+ * writes normally complete in a cycle or two, so one read should suffice.
+ * The very first read exists to flush the posted write to the device.
+ */
+static int wrreg_wait(struct adapter *adapter, unsigned int addr, u32 val)
+{
+       t3_write_reg(adapter, addr, val);
+       t3_read_reg(adapter, addr);     /* flush */
+       if (!(t3_read_reg(adapter, addr) & F_BUSY))
+               return 0;
+       CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr);
+       return -EIO;
+}
+
+static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type)
+{
+       static const unsigned int mc7_mode[] = {
+               0x632, 0x642, 0x652, 0x432, 0x442
+       };
+       static const struct mc7_timing_params mc7_timings[] = {
+               {12, 3, 4, {20, 28, 34, 52, 0}, 15, 6, 4},
+               {12, 4, 5, {20, 28, 34, 52, 0}, 16, 7, 4},
+               {12, 5, 6, {20, 28, 34, 52, 0}, 17, 8, 4},
+               {9, 3, 4, {15, 21, 26, 39, 0}, 12, 6, 4},
+               {9, 4, 5, {15, 21, 26, 39, 0}, 13, 7, 4}
+       };
+
+       u32 val;
+       unsigned int width, density, slow, attempts;
+       struct adapter *adapter = mc7->adapter;
+       const struct mc7_timing_params *p = &mc7_timings[mem_type];
+
+       val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
+       slow = val & F_SLOW;
+       width = G_WIDTH(val);
+       density = G_DEN(val);
+
+       t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN);
+       val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);    /* flush */
+       msleep(1);
+
+       if (!slow) {
+               t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN);
+               t3_read_reg(adapter, mc7->offset + A_MC7_CAL);
+               msleep(1);
+               if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) &
+                   (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) {
+                       CH_ERR(adapter, "%s MC7 calibration timed out\n",
+                              mc7->name);
+                       goto out_fail;
+               }
+       }
+
+       t3_write_reg(adapter, mc7->offset + A_MC7_PARM,
+                    V_ACTTOPREDLY(p->ActToPreDly) |
+                    V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) |
+                    V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) |
+                    V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly));
+
+       t3_write_reg(adapter, mc7->offset + A_MC7_CFG,
+                    val | F_CLKEN | F_TERM150);
+       t3_read_reg(adapter, mc7->offset + A_MC7_CFG);  /* flush */
+
+       if (!slow)
+               t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB,
+                                F_DLLENB);
+       udelay(1);
+
+       val = slow ? 3 : 6;
+       if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
+           wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) ||
+           wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) ||
+           wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
+               goto out_fail;
+
+       if (!slow) {
+               t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100);
+               t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLRST, 0);
+               udelay(5);
+       }
+
+       if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
+           wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
+           wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
+           wrreg_wait(adapter, mc7->offset + A_MC7_MODE,
+                      mc7_mode[mem_type]) ||
+           wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) ||
+           wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
+               goto out_fail;
+
+       /* clock value is in KHz */
+       mc7_clock = mc7_clock * 7812 + mc7_clock / 2;   /* ns */
+       mc7_clock /= 1000000;   /* KHz->MHz, ns->us */
+
+       t3_write_reg(adapter, mc7->offset + A_MC7_REF,
+                    F_PERREFEN | V_PREREFDIV(mc7_clock));
+       t3_read_reg(adapter, mc7->offset + A_MC7_REF);  /* flush */
+
+       t3_write_reg(adapter, mc7->offset + A_MC7_ECC, F_ECCGENEN | F_ECCCHKEN);
+       t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0);
+       t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0);
+       t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END,
+                    (mc7->size << width) - 1);
+       t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1));
+       t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);      /* flush */
+
+       attempts = 50;
+       do {
+               msleep(250);
+               val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);
+       } while ((val & F_BUSY) && --attempts);
+       if (val & F_BUSY) {
+               CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name);
+               goto out_fail;
+       }
+
+       /* Enable normal memory accesses. */
+       t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY);
+       return 0;
+
+out_fail:
+       return -1;
+}
+
+static void config_pcie(struct adapter *adap)
+{
+       static const u16 ack_lat[4][6] = {
+               {237, 416, 559, 1071, 2095, 4143},
+               {128, 217, 289, 545, 1057, 2081},
+               {73, 118, 154, 282, 538, 1050},
+               {67, 107, 86, 150, 278, 534}
+       };
+       static const u16 rpl_tmr[4][6] = {
+               {711, 1248, 1677, 3213, 6285, 12429},
+               {384, 651, 867, 1635, 3171, 6243},
+               {219, 354, 462, 846, 1614, 3150},
+               {201, 321, 258, 450, 834, 1602}
+       };
+
+       u16 val;
+       unsigned int log2_width, pldsize;
+       unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
+
+       pci_read_config_word(adap->pdev,
+                            adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL,
+                            &val);
+       pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
+       pci_read_config_word(adap->pdev,
+                            adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL,
+                            &val);
+
+       fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0));
+       fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx :
+           G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE));
+       log2_width = fls(adap->params.pci.width) - 1;
+       acklat = ack_lat[log2_width][pldsize];
+       if (val & 1)            /* check LOsEnable */
+               acklat += fst_trn_tx * 4;
+       rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4;
+
+       if (adap->params.rev == 0)
+               t3_set_reg_field(adap, A_PCIE_PEX_CTRL1,
+                                V_T3A_ACKLAT(M_T3A_ACKLAT),
+                                V_T3A_ACKLAT(acklat));
+       else
+               t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT),
+                                V_ACKLAT(acklat));
+
+       t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT),
+                        V_REPLAYLMT(rpllmt));
+
+       t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
+       t3_set_reg_field(adap, A_PCIE_CFG, F_PCIE_CLIDECEN, F_PCIE_CLIDECEN);
+}
+
+/*
+ * Initialize and configure T3 HW modules.  This performs the
+ * initialization steps that need to be done once after a card is reset.
+ * MAC and PHY initialization is handled separarely whenever a port is enabled.
+ *
+ * fw_params are passed to FW and their value is platform dependent.  Only the
+ * top 8 bits are available for use, the rest must be 0.
+ */
+int t3_init_hw(struct adapter *adapter, u32 fw_params)
+{
+       int err = -EIO, attempts = 100;
+       const struct vpd_params *vpd = &adapter->params.vpd;
+
+       if (adapter->params.rev > 0)
+               calibrate_xgm_t3b(adapter);
+       else if (calibrate_xgm(adapter))
+               goto out_err;
+
+       if (vpd->mclk) {
+               partition_mem(adapter, &adapter->params.tp);
+
+               if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) ||
+                   mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) ||
+                   mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) ||
+                   t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers,
+                               adapter->params.mc5.nfilters,
+                               adapter->params.mc5.nroutes))
+                       goto out_err;
+       }
+
+       if (tp_init(adapter, &adapter->params.tp))
+               goto out_err;
+
+       t3_tp_set_coalescing_size(adapter,
+                                 min(adapter->params.sge.max_pkt_size,
+                                     MAX_RX_COALESCING_LEN), 1);
+       t3_tp_set_max_rxsize(adapter,
+                            min(adapter->params.sge.max_pkt_size, 16384U));
+       ulp_config(adapter, &adapter->params.tp);
+
+       if (is_pcie(adapter))
+               config_pcie(adapter);
+       else
+               t3_set_reg_field(adapter, A_PCIX_CFG, 0, F_CLIDECEN);
+
+       t3_write_reg(adapter, A_PM1_RX_CFG, 0xf000f000);
+       init_hw_for_avail_ports(adapter, adapter->params.nports);
+       t3_sge_init(adapter, &adapter->params.sge);
+
+       t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params);
+       t3_write_reg(adapter, A_CIM_BOOT_CFG,
+                    V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
+       t3_read_reg(adapter, A_CIM_BOOT_CFG);   /* flush */
+
+       do {                    /* wait for uP to initialize */
+               msleep(20);
+       } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts);
+       if (!attempts)
+               goto out_err;
+
+       err = 0;
+out_err:
+       return err;
+}
+
+/**
+ *     get_pci_mode - determine a card's PCI mode
+ *     @adapter: the adapter
+ *     @p: where to store the PCI settings
+ *
+ *     Determines a card's PCI mode and associated parameters, such as speed
+ *     and width.
+ */
+static void __devinit get_pci_mode(struct adapter *adapter,
+                                  struct pci_params *p)
+{
+       static unsigned short speed_map[] = { 33, 66, 100, 133 };
+       u32 pci_mode, pcie_cap;
+
+       pcie_cap = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
+       if (pcie_cap) {
+               u16 val;
+
+               p->variant = PCI_VARIANT_PCIE;
+               p->pcie_cap_addr = pcie_cap;
+               pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA,
+                                       &val);
+               p->width = (val >> 4) & 0x3f;
+               return;
+       }
+
+       pci_mode = t3_read_reg(adapter, A_PCIX_MODE);
+       p->speed = speed_map[G_PCLKRANGE(pci_mode)];
+       p->width = (pci_mode & F_64BIT) ? 64 : 32;
+       pci_mode = G_PCIXINITPAT(pci_mode);
+       if (pci_mode == 0)
+               p->variant = PCI_VARIANT_PCI;
+       else if (pci_mode < 4)
+               p->variant = PCI_VARIANT_PCIX_MODE1_PARITY;
+       else if (pci_mode < 8)
+               p->variant = PCI_VARIANT_PCIX_MODE1_ECC;
+       else
+               p->variant = PCI_VARIANT_PCIX_266_MODE2;
+}
+
+/**
+ *     init_link_config - initialize a link's SW state
+ *     @lc: structure holding the link state
+ *     @ai: information about the current card
+ *
+ *     Initializes the SW state maintained for each link, including the link's
+ *     capabilities and default speed/duplex/flow-control/autonegotiation
+ *     settings.
+ */
+static void __devinit init_link_config(struct link_config *lc,
+                                      unsigned int caps)
+{
+       lc->supported = caps;
+       lc->requested_speed = lc->speed = SPEED_INVALID;
+       lc->requested_duplex = lc->duplex = DUPLEX_INVALID;
+       lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
+       if (lc->supported & SUPPORTED_Autoneg) {
+               lc->advertising = lc->supported;
+               lc->autoneg = AUTONEG_ENABLE;
+               lc->requested_fc |= PAUSE_AUTONEG;
+       } else {
+               lc->advertising = 0;
+               lc->autoneg = AUTONEG_DISABLE;
+       }
+}
+
+/**
+ *     mc7_calc_size - calculate MC7 memory size
+ *     @cfg: the MC7 configuration
+ *
+ *     Calculates the size of an MC7 memory in bytes from the value of its
+ *     configuration register.
+ */
+static unsigned int __devinit mc7_calc_size(u32 cfg)
+{
+       unsigned int width = G_WIDTH(cfg);
+       unsigned int banks = !!(cfg & F_BKS) + 1;
+       unsigned int org = !!(cfg & F_ORG) + 1;
+       unsigned int density = G_DEN(cfg);
+       unsigned int MBs = ((256 << density) * banks) / (org << width);
+
+       return MBs << 20;
+}
+
+static void __devinit mc7_prep(struct adapter *adapter, struct mc7 *mc7,
+                              unsigned int base_addr, const char *name)
+{
+       u32 cfg;
+
+       mc7->adapter = adapter;
+       mc7->name = name;
+       mc7->offset = base_addr - MC7_PMRX_BASE_ADDR;
+       cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
+       mc7->size = mc7_calc_size(cfg);
+       mc7->width = G_WIDTH(cfg);
+}
+
+void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
+{
+       mac->adapter = adapter;
+       mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
+       mac->nucast = 1;
+
+       if (adapter->params.rev == 0 && uses_xaui(adapter)) {
+               t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset,
+                            is_10G(adapter) ? 0x2901c04 : 0x2301c04);
+               t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset,
+                                F_ENRGMII, 0);
+       }
+}
+
+void early_hw_init(struct adapter *adapter, const struct adapter_info *ai)
+{
+       u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2);
+
+       mi1_init(adapter, ai);
+       t3_write_reg(adapter, A_I2C_CFG,        /* set for 80KHz */
+                    V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1));
+       t3_write_reg(adapter, A_T3DBG_GPIO_EN,
+                    ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL);
+
+       if (adapter->params.rev == 0 || !uses_xaui(adapter))
+               val |= F_ENRGMII;
+
+       /* Enable MAC clocks so we can access the registers */
+       t3_write_reg(adapter, A_XGM_PORT_CFG, val);
+       t3_read_reg(adapter, A_XGM_PORT_CFG);
+
+       val |= F_CLKDIVRESET_;
+       t3_write_reg(adapter, A_XGM_PORT_CFG, val);
+       t3_read_reg(adapter, A_XGM_PORT_CFG);
+       t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val);
+       t3_read_reg(adapter, A_XGM_PORT_CFG);
+}
+
+/*
+ * Reset the adapter.  PCIe cards lose their config space during reset, PCI-X
+ * ones don't.
+ */
+int t3_reset_adapter(struct adapter *adapter)
+{
+       int i;
+       uint16_t devid = 0;
+
+       if (is_pcie(adapter))
+               pci_save_state(adapter->pdev);
+       t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE);
+
+       /*
+        * Delay. Give Some time to device to reset fully.
+        * XXX The delay time should be modified.
+        */
+       for (i = 0; i < 10; i++) {
+               msleep(50);
+               pci_read_config_word(adapter->pdev, 0x00, &devid);
+               if (devid == 0x1425)
+                       break;
+       }
+
+       if (devid != 0x1425)
+               return -1;
+
+       if (is_pcie(adapter))
+               pci_restore_state(adapter->pdev);
+       return 0;
+}
+
+/*
+ * Initialize adapter SW state for the various HW modules, set initial values
+ * for some adapter tunables, take PHYs out of reset, and initialize the MDIO
+ * interface.
+ */
+int __devinit t3_prep_adapter(struct adapter *adapter,
+                             const struct adapter_info *ai, int reset)
+{
+       int ret;
+       unsigned int i, j = 0;
+
+       get_pci_mode(adapter, &adapter->params.pci);
+
+       adapter->params.info = ai;
+       adapter->params.nports = ai->nports;
+       adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
+       adapter->params.linkpoll_period = 0;
+       adapter->params.stats_update_period = is_10G(adapter) ?
+           MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
+       adapter->params.pci.vpd_cap_addr =
+           pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD);
+       ret = get_vpd_params(adapter, &adapter->params.vpd);
+       if (ret < 0)
+               return ret;
+
+       if (reset && t3_reset_adapter(adapter))
+               return -1;
+
+       t3_sge_prep(adapter, &adapter->params.sge);
+
+       if (adapter->params.vpd.mclk) {
+               struct tp_params *p = &adapter->params.tp;
+
+               mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX");
+               mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX");
+               mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM");
+
+               p->nchan = ai->nports;
+               p->pmrx_size = t3_mc7_size(&adapter->pmrx);
+               p->pmtx_size = t3_mc7_size(&adapter->pmtx);
+               p->cm_size = t3_mc7_size(&adapter->cm);
+               p->chan_rx_size = p->pmrx_size / 2;     /* only 1 Rx channel */
+               p->chan_tx_size = p->pmtx_size / p->nchan;
+               p->rx_pg_size = 64 * 1024;
+               p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024;
+               p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size);
+               p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size);
+               p->ntimer_qs = p->cm_size >= (128 << 20) ||
+                   adapter->params.rev > 0 ? 12 : 6;
+
+               adapter->params.mc5.nservers = DEFAULT_NSERVERS;
+               adapter->params.mc5.nfilters = adapter->params.rev > 0 ?
+                   DEFAULT_NFILTERS : 0;
+               adapter->params.mc5.nroutes = 0;
+               t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT);
+
+               init_mtus(adapter->params.mtus);
+               init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
+       }
+
+       early_hw_init(adapter, ai);
+
+       for_each_port(adapter, i) {
+               u8 hw_addr[6];
+               struct port_info *p = adap2pinfo(adapter, i);
+
+               while (!adapter->params.vpd.port_type[j])
+                       ++j;
+
+               p->port_type = &port_types[adapter->params.vpd.port_type[j]];
+               p->port_type->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
+                                      ai->mdio_ops);
+               mac_prep(&p->mac, adapter, j);
+               ++j;
+
+               /*
+                * The VPD EEPROM stores the base Ethernet address for the
+                * card.  A port's address is derived from the base by adding
+                * the port's index to the base's low octet.
+                */
+               memcpy(hw_addr, adapter->params.vpd.eth_base, 5);
+               hw_addr[5] = adapter->params.vpd.eth_base[5] + i;
+
+               memcpy(adapter->port[i]->dev_addr, hw_addr,
+                      ETH_ALEN);
+               memcpy(adapter->port[i]->perm_addr, hw_addr,
+                      ETH_ALEN);
+               init_link_config(&p->link_config, p->port_type->caps);
+               p->phy.ops->power_down(&p->phy, 1);
+               if (!(p->port_type->caps & SUPPORTED_IRQ))
+                       adapter->params.linkpoll_period = 10;
+       }
+
+       return 0;
+}
+
+void t3_led_ready(struct adapter *adapter)
+{
+       t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
+                        F_GPIO0_OUT_VAL);
+}
diff --git a/drivers/net/cxgb3/t3cdev.h b/drivers/net/cxgb3/t3cdev.h
new file mode 100644 (file)
index 0000000..9af3bcd
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2006-2007 Chelsio Communications.  All rights reserved.
+ * Copyright (C) 2006-2007 Open Grid Computing, Inc.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _T3CDEV_H_
+#define _T3CDEV_H_
+
+#include <linux/list.h>
+#include <asm/atomic.h>
+#include <asm/semaphore.h>
+#include <linux/netdevice.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <net/neighbour.h>
+
+#define T3CNAMSIZ 16
+
+/* Get the t3cdev associated with a net_device */
+#define T3CDEV(netdev) (struct t3cdev *)(netdev->priv)
+
+struct cxgb3_client;
+
+enum t3ctype {
+       T3A = 0,
+       T3B
+};
+
+struct t3cdev {
+       char name[T3CNAMSIZ];   /* T3C device name */
+       enum t3ctype type;
+       struct list_head ofld_dev_list; /* for list linking */
+       struct net_device *lldev;       /* LL dev associated with T3C messages */
+       struct proc_dir_entry *proc_dir;        /* root of proc dir for this T3C */
+       int (*send)(struct t3cdev *dev, struct sk_buff *skb);
+       int (*recv)(struct t3cdev *dev, struct sk_buff **skb, int n);
+       int (*ctl)(struct t3cdev *dev, unsigned int req, void *data);
+       void (*neigh_update)(struct t3cdev *dev, struct neighbour *neigh);
+       void *priv;             /* driver private data */
+       void *l2opt;            /* optional layer 2 data */
+       void *l3opt;            /* optional layer 3 data */
+       void *l4opt;            /* optional layer 4 data */
+       void *ulp;              /* ulp stuff */
+};
+
+#endif                         /* _T3CDEV_H_ */
diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h
new file mode 100644 (file)
index 0000000..2b67dd5
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2003-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* $Date: 2006/10/31 18:57:51 $ $RCSfile: version.h,v $ $Revision: 1.3 $ */
+#ifndef __CHELSIO_VERSION_H
+#define __CHELSIO_VERSION_H
+#define DRV_DESC "Chelsio T3 Network Driver"
+#define DRV_NAME "cxgb3"
+/* Driver version */
+#define DRV_VERSION "1.0"
+#endif                         /* __CHELSIO_VERSION_H */
diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c
new file mode 100644 (file)
index 0000000..eee4285
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+
+/* VSC8211 PHY specific registers. */
+enum {
+       VSC8211_INTR_ENABLE = 25,
+       VSC8211_INTR_STATUS = 26,
+       VSC8211_AUX_CTRL_STAT = 28,
+};
+
+enum {
+       VSC_INTR_RX_ERR = 1 << 0,
+       VSC_INTR_MS_ERR = 1 << 1,       /* master/slave resolution error */
+       VSC_INTR_CABLE = 1 << 2,        /* cable impairment */
+       VSC_INTR_FALSE_CARR = 1 << 3,   /* false carrier */
+       VSC_INTR_MEDIA_CHG = 1 << 4,    /* AMS media change */
+       VSC_INTR_RX_FIFO = 1 << 5,      /* Rx FIFO over/underflow */
+       VSC_INTR_TX_FIFO = 1 << 6,      /* Tx FIFO over/underflow */
+       VSC_INTR_DESCRAMBL = 1 << 7,    /* descrambler lock-lost */
+       VSC_INTR_SYMBOL_ERR = 1 << 8,   /* symbol error */
+       VSC_INTR_NEG_DONE = 1 << 10,    /* autoneg done */
+       VSC_INTR_NEG_ERR = 1 << 11,     /* autoneg error */
+       VSC_INTR_LINK_CHG = 1 << 13,    /* link change */
+       VSC_INTR_ENABLE = 1 << 15,      /* interrupt enable */
+};
+
+#define CFG_CHG_INTR_MASK (VSC_INTR_LINK_CHG | VSC_INTR_NEG_ERR | \
+                          VSC_INTR_NEG_DONE)
+#define INTR_MASK (CFG_CHG_INTR_MASK | VSC_INTR_TX_FIFO | VSC_INTR_RX_FIFO | \
+                  VSC_INTR_ENABLE)
+
+/* PHY specific auxiliary control & status register fields */
+#define S_ACSR_ACTIPHY_TMR    0
+#define M_ACSR_ACTIPHY_TMR    0x3
+#define V_ACSR_ACTIPHY_TMR(x) ((x) << S_ACSR_ACTIPHY_TMR)
+
+#define S_ACSR_SPEED    3
+#define M_ACSR_SPEED    0x3
+#define G_ACSR_SPEED(x) (((x) >> S_ACSR_SPEED) & M_ACSR_SPEED)
+
+#define S_ACSR_DUPLEX 5
+#define F_ACSR_DUPLEX (1 << S_ACSR_DUPLEX)
+
+#define S_ACSR_ACTIPHY 6
+#define F_ACSR_ACTIPHY (1 << S_ACSR_ACTIPHY)
+
+/*
+ * Reset the PHY.  This PHY completes reset immediately so we never wait.
+ */
+static int vsc8211_reset(struct cphy *cphy, int wait)
+{
+       return t3_phy_reset(cphy, 0, 0);
+}
+
+static int vsc8211_intr_enable(struct cphy *cphy)
+{
+       return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, INTR_MASK);
+}
+
+static int vsc8211_intr_disable(struct cphy *cphy)
+{
+       return mdio_write(cphy, 0, VSC8211_INTR_ENABLE, 0);
+}
+
+static int vsc8211_intr_clear(struct cphy *cphy)
+{
+       u32 val;
+
+       /* Clear PHY interrupts by reading the register. */
+       return mdio_read(cphy, 0, VSC8211_INTR_STATUS, &val);
+}
+
+static int vsc8211_autoneg_enable(struct cphy *cphy)
+{
+       return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
+                                  BMCR_ANENABLE | BMCR_ANRESTART);
+}
+
+static int vsc8211_autoneg_restart(struct cphy *cphy)
+{
+       return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN | BMCR_ISOLATE,
+                                  BMCR_ANRESTART);
+}
+
+static int vsc8211_get_link_status(struct cphy *cphy, int *link_ok,
+                                  int *speed, int *duplex, int *fc)
+{
+       unsigned int bmcr, status, lpa, adv;
+       int err, sp = -1, dplx = -1, pause = 0;
+
+       err = mdio_read(cphy, 0, MII_BMCR, &bmcr);
+       if (!err)
+               err = mdio_read(cphy, 0, MII_BMSR, &status);
+       if (err)
+               return err;
+
+       if (link_ok) {
+               /*
+                * BMSR_LSTATUS is latch-low, so if it is 0 we need to read it
+                * once more to get the current link state.
+                */
+               if (!(status & BMSR_LSTATUS))
+                       err = mdio_read(cphy, 0, MII_BMSR, &status);
+               if (err)
+                       return err;
+               *link_ok = (status & BMSR_LSTATUS) != 0;
+       }
+       if (!(bmcr & BMCR_ANENABLE)) {
+               dplx = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
+               if (bmcr & BMCR_SPEED1000)
+                       sp = SPEED_1000;
+               else if (bmcr & BMCR_SPEED100)
+                       sp = SPEED_100;
+               else
+                       sp = SPEED_10;
+       } else if (status & BMSR_ANEGCOMPLETE) {
+               err = mdio_read(cphy, 0, VSC8211_AUX_CTRL_STAT, &status);
+               if (err)
+                       return err;
+
+               dplx = (status & F_ACSR_DUPLEX) ? DUPLEX_FULL : DUPLEX_HALF;
+               sp = G_ACSR_SPEED(status);
+               if (sp == 0)
+                       sp = SPEED_10;
+               else if (sp == 1)
+                       sp = SPEED_100;
+               else
+                       sp = SPEED_1000;
+
+               if (fc && dplx == DUPLEX_FULL) {
+                       err = mdio_read(cphy, 0, MII_LPA, &lpa);
+                       if (!err)
+                               err = mdio_read(cphy, 0, MII_ADVERTISE, &adv);
+                       if (err)
+                               return err;
+
+                       if (lpa & adv & ADVERTISE_PAUSE_CAP)
+                               pause = PAUSE_RX | PAUSE_TX;
+                       else if ((lpa & ADVERTISE_PAUSE_CAP) &&
+                                (lpa & ADVERTISE_PAUSE_ASYM) &&
+                                (adv & ADVERTISE_PAUSE_ASYM))
+                               pause = PAUSE_TX;
+                       else if ((lpa & ADVERTISE_PAUSE_ASYM) &&
+                                (adv & ADVERTISE_PAUSE_CAP))
+                               pause = PAUSE_RX;
+               }
+       }
+       if (speed)
+               *speed = sp;
+       if (duplex)
+               *duplex = dplx;
+       if (fc)
+               *fc = pause;
+       return 0;
+}
+
+static int vsc8211_power_down(struct cphy *cphy, int enable)
+{
+       return t3_mdio_change_bits(cphy, 0, MII_BMCR, BMCR_PDOWN,
+                                  enable ? BMCR_PDOWN : 0);
+}
+
+static int vsc8211_intr_handler(struct cphy *cphy)
+{
+       unsigned int cause;
+       int err, cphy_cause = 0;
+
+       err = mdio_read(cphy, 0, VSC8211_INTR_STATUS, &cause);
+       if (err)
+               return err;
+
+       cause &= INTR_MASK;
+       if (cause & CFG_CHG_INTR_MASK)
+               cphy_cause |= cphy_cause_link_change;
+       if (cause & (VSC_INTR_RX_FIFO | VSC_INTR_TX_FIFO))
+               cphy_cause |= cphy_cause_fifo_error;
+       return cphy_cause;
+}
+
+static struct cphy_ops vsc8211_ops = {
+       .reset = vsc8211_reset,
+       .intr_enable = vsc8211_intr_enable,
+       .intr_disable = vsc8211_intr_disable,
+       .intr_clear = vsc8211_intr_clear,
+       .intr_handler = vsc8211_intr_handler,
+       .autoneg_enable = vsc8211_autoneg_enable,
+       .autoneg_restart = vsc8211_autoneg_restart,
+       .advertise = t3_phy_advertise,
+       .set_speed_duplex = t3_set_phy_speed_duplex,
+       .get_link_status = vsc8211_get_link_status,
+       .power_down = vsc8211_power_down,
+};
+
+void t3_vsc8211_phy_prep(struct cphy *phy, struct adapter *adapter,
+                        int phy_addr, const struct mdio_ops *mdio_ops)
+{
+       cphy_init(phy, adapter, phy_addr, &vsc8211_ops, mdio_ops);
+}
diff --git a/drivers/net/cxgb3/xgmac.c b/drivers/net/cxgb3/xgmac.c
new file mode 100644 (file)
index 0000000..907a272
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ * Copyright (c) 2005-2007 Chelsio, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "common.h"
+#include "regs.h"
+
+/*
+ * # of exact address filters.  The first one is used for the station address,
+ * the rest are available for multicast addresses.
+ */
+#define EXACT_ADDR_FILTERS 8
+
+static inline int macidx(const struct cmac *mac)
+{
+       return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
+}
+
+static void xaui_serdes_reset(struct cmac *mac)
+{
+       static const unsigned int clear[] = {
+               F_PWRDN0 | F_PWRDN1, F_RESETPLL01, F_RESET0 | F_RESET1,
+               F_PWRDN2 | F_PWRDN3, F_RESETPLL23, F_RESET2 | F_RESET3
+       };
+
+       int i;
+       struct adapter *adap = mac->adapter;
+       u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
+
+       t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
+                    F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
+                    F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
+                    F_RESETPLL23 | F_RESETPLL01);
+       t3_read_reg(adap, ctrl);
+       udelay(15);
+
+       for (i = 0; i < ARRAY_SIZE(clear); i++) {
+               t3_set_reg_field(adap, ctrl, clear[i], 0);
+               udelay(15);
+       }
+}
+
+void t3b_pcs_reset(struct cmac *mac)
+{
+       t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
+                        F_PCS_RESET_, 0);
+       udelay(20);
+       t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
+                        F_PCS_RESET_);
+}
+
+int t3_mac_reset(struct cmac *mac)
+{
+       static const struct addr_val_pair mac_reset_avp[] = {
+               {A_XGM_TX_CTRL, 0},
+               {A_XGM_RX_CTRL, 0},
+               {A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
+                F_RMFCS | F_ENJUMBO | F_ENHASHMCAST},
+               {A_XGM_RX_HASH_LOW, 0},
+               {A_XGM_RX_HASH_HIGH, 0},
+               {A_XGM_RX_EXACT_MATCH_LOW_1, 0},
+               {A_XGM_RX_EXACT_MATCH_LOW_2, 0},
+               {A_XGM_RX_EXACT_MATCH_LOW_3, 0},
+               {A_XGM_RX_EXACT_MATCH_LOW_4, 0},
+               {A_XGM_RX_EXACT_MATCH_LOW_5, 0},
+               {A_XGM_RX_EXACT_MATCH_LOW_6, 0},
+               {A_XGM_RX_EXACT_MATCH_LOW_7, 0},
+               {A_XGM_RX_EXACT_MATCH_LOW_8, 0},
+               {A_XGM_STAT_CTRL, F_CLRSTATS}
+       };
+       u32 val;
+       struct adapter *adap = mac->adapter;
+       unsigned int oft = mac->offset;
+
+       t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
+       t3_read_reg(adap, A_XGM_RESET_CTRL + oft);      /* flush */
+
+       t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
+       t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
+                        F_RXSTRFRWRD | F_DISERRFRAMES,
+                        uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
+
+       if (uses_xaui(adap)) {
+               if (adap->params.rev == 0) {
+                       t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
+                                        F_RXENABLE | F_TXENABLE);
+                       if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
+                                           F_CMULOCK, 1, 5, 2)) {
+                               CH_ERR(adap,
+                                      "MAC %d XAUI SERDES CMU lock failed\n",
+                                      macidx(mac));
+                               return -1;
+                       }
+                       t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
+                                        F_SERDESRESET_);
+               } else
+                       xaui_serdes_reset(mac);
+       }
+
+       if (adap->params.rev > 0)
+               t3_write_reg(adap, A_XGM_PAUSE_TIMER + oft, 0xf000);
+
+       val = F_MAC_RESET_;
+       if (is_10G(adap))
+               val |= F_PCS_RESET_;
+       else if (uses_xaui(adap))
+               val |= F_PCS_RESET_ | F_XG2G_RESET_;
+       else
+               val |= F_RGMII_RESET_ | F_XG2G_RESET_;
+       t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
+       t3_read_reg(adap, A_XGM_RESET_CTRL + oft);      /* flush */
+       if ((val & F_PCS_RESET_) && adap->params.rev) {
+               msleep(1);
+               t3b_pcs_reset(mac);
+       }
+
+       memset(&mac->stats, 0, sizeof(mac->stats));
+       return 0;
+}
+
+/*
+ * Set the exact match register 'idx' to recognize the given Ethernet address.
+ */
+static void set_addr_filter(struct cmac *mac, int idx, const u8 * addr)
+{
+       u32 addr_lo, addr_hi;
+       unsigned int oft = mac->offset + idx * 8;
+
+       addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
+       addr_hi = (addr[5] << 8) | addr[4];
+
+       t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
+       t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
+}
+
+/* Set one of the station's unicast MAC addresses. */
+int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
+{
+       if (idx >= mac->nucast)
+               return -EINVAL;
+       set_addr_filter(mac, idx, addr);
+       return 0;
+}
+
+/*
+ * Specify the number of exact address filters that should be reserved for
+ * unicast addresses.  Caller should reload the unicast and multicast addresses
+ * after calling this.
+ */
+int t3_mac_set_num_ucast(struct cmac *mac, int n)
+{
+       if (n > EXACT_ADDR_FILTERS)
+               return -EINVAL;
+       mac->nucast = n;
+       return 0;
+}
+
+/* Calculate the RX hash filter index of an Ethernet address */
+static int hash_hw_addr(const u8 * addr)
+{
+       int hash = 0, octet, bit, i = 0, c;
+
+       for (octet = 0; octet < 6; ++octet)
+               for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
+                       hash ^= (c & 1) << i;
+                       if (++i == 6)
+                               i = 0;
+               }
+       return hash;
+}
+
+int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
+{
+       u32 val, hash_lo, hash_hi;
+       struct adapter *adap = mac->adapter;
+       unsigned int oft = mac->offset;
+
+       val = t3_read_reg(adap, A_XGM_RX_CFG + oft) & ~F_COPYALLFRAMES;
+       if (rm->dev->flags & IFF_PROMISC)
+               val |= F_COPYALLFRAMES;
+       t3_write_reg(adap, A_XGM_RX_CFG + oft, val);
+
+       if (rm->dev->flags & IFF_ALLMULTI)
+               hash_lo = hash_hi = 0xffffffff;
+       else {
+               u8 *addr;
+               int exact_addr_idx = mac->nucast;
+
+               hash_lo = hash_hi = 0;
+               while ((addr = t3_get_next_mcaddr(rm)))
+                       if (exact_addr_idx < EXACT_ADDR_FILTERS)
+                               set_addr_filter(mac, exact_addr_idx++, addr);
+                       else {
+                               int hash = hash_hw_addr(addr);
+
+                               if (hash < 32)
+                                       hash_lo |= (1 << hash);
+                               else
+                                       hash_hi |= (1 << (hash - 32));
+                       }
+       }
+
+       t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
+       t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
+       return 0;
+}
+
+int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
+{
+       int hwm, lwm;
+       unsigned int thres, v;
+       struct adapter *adap = mac->adapter;
+
+       /*
+        * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't.  The HW max
+        * packet size register includes header, but not FCS.
+        */
+       mtu += 14;
+       if (mtu > MAX_FRAME_SIZE - 4)
+               return -EINVAL;
+       t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
+
+       /*
+        * Adjust the PAUSE frame watermarks.  We always set the LWM, and the
+        * HWM only if flow-control is enabled.
+        */
+       hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, MAC_RXFIFO_SIZE / 2U);
+       hwm = min(hwm, 3 * MAC_RXFIFO_SIZE / 4 + 1024);
+       lwm = hwm - 1024;
+       v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
+       v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
+       v |= V_RXFIFOPAUSELWM(lwm / 8);
+       if (G_RXFIFOPAUSEHWM(v))
+               v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
+                   V_RXFIFOPAUSEHWM(hwm / 8);
+       t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
+
+       /* Adjust the TX FIFO threshold based on the MTU */
+       thres = (adap->params.vpd.cclk * 1000) / 15625;
+       thres = (thres * mtu) / 1000;
+       if (is_10G(adap))
+               thres /= 10;
+       thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
+       thres = max(thres, 8U); /* need at least 8 */
+       t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
+                        V_TXFIFOTHRESH(M_TXFIFOTHRESH), V_TXFIFOTHRESH(thres));
+       return 0;
+}
+
+int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
+{
+       u32 val;
+       struct adapter *adap = mac->adapter;
+       unsigned int oft = mac->offset;
+
+       if (duplex >= 0 && duplex != DUPLEX_FULL)
+               return -EINVAL;
+       if (speed >= 0) {
+               if (speed == SPEED_10)
+                       val = V_PORTSPEED(0);
+               else if (speed == SPEED_100)
+                       val = V_PORTSPEED(1);
+               else if (speed == SPEED_1000)
+                       val = V_PORTSPEED(2);
+               else if (speed == SPEED_10000)
+                       val = V_PORTSPEED(3);
+               else
+                       return -EINVAL;
+
+               t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
+                                V_PORTSPEED(M_PORTSPEED), val);
+       }
+
+       val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
+       val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
+       if (fc & PAUSE_TX)
+               val |= V_RXFIFOPAUSEHWM(G_RXFIFOPAUSELWM(val) + 128);   /* +1KB */
+       t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
+
+       t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
+                        (fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
+       return 0;
+}
+
+int t3_mac_enable(struct cmac *mac, int which)
+{
+       int idx = macidx(mac);
+       struct adapter *adap = mac->adapter;
+       unsigned int oft = mac->offset;
+
+       if (which & MAC_DIRECTION_TX) {
+               t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
+               t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
+               t3_write_reg(adap, A_TP_PIO_DATA, 0xbf000001);
+               t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
+               t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
+       }
+       if (which & MAC_DIRECTION_RX)
+               t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
+       return 0;
+}
+
+int t3_mac_disable(struct cmac *mac, int which)
+{
+       int idx = macidx(mac);
+       struct adapter *adap = mac->adapter;
+
+       if (which & MAC_DIRECTION_TX) {
+               t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
+               t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
+               t3_write_reg(adap, A_TP_PIO_DATA, 0xc000001f);
+               t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
+               t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 0);
+       }
+       if (which & MAC_DIRECTION_RX)
+               t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
+       return 0;
+}
+
+/*
+ * This function is called periodically to accumulate the current values of the
+ * RMON counters into the port statistics.  Since the packet counters are only
+ * 32 bits they can overflow in ~286 secs at 10G, so the function should be
+ * called more frequently than that.  The byte counters are 45-bit wide, they
+ * would overflow in ~7.8 hours.
+ */
+const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
+{
+#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
+#define RMON_UPDATE(mac, name, reg) \
+       (mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
+#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
+       (mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
+                            ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
+
+       u32 v, lo;
+
+       RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
+       RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
+       RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
+       RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
+       RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
+       RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
+       RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
+       RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
+       RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
+
+       RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
+       mac->stats.rx_too_long += RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
+
+       RMON_UPDATE(mac, rx_frames_64, RX_64B_FRAMES);
+       RMON_UPDATE(mac, rx_frames_65_127, RX_65_127B_FRAMES);
+       RMON_UPDATE(mac, rx_frames_128_255, RX_128_255B_FRAMES);
+       RMON_UPDATE(mac, rx_frames_256_511, RX_256_511B_FRAMES);
+       RMON_UPDATE(mac, rx_frames_512_1023, RX_512_1023B_FRAMES);
+       RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
+       RMON_UPDATE(mac, rx_frames_1519_max, RX_1519_MAXB_FRAMES);
+
+       RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
+       RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
+       RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
+       RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
+       RMON_UPDATE(mac, tx_pause, TX_PAUSE);
+       /* This counts error frames in general (bad FCS, underrun, etc). */
+       RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
+
+       RMON_UPDATE(mac, tx_frames_64, TX_64B_FRAMES);
+       RMON_UPDATE(mac, tx_frames_65_127, TX_65_127B_FRAMES);
+       RMON_UPDATE(mac, tx_frames_128_255, TX_128_255B_FRAMES);
+       RMON_UPDATE(mac, tx_frames_256_511, TX_256_511B_FRAMES);
+       RMON_UPDATE(mac, tx_frames_512_1023, TX_512_1023B_FRAMES);
+       RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
+       RMON_UPDATE(mac, tx_frames_1519_max, TX_1519_MAXB_FRAMES);
+
+       /* The next stat isn't clear-on-read. */
+       t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
+       v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
+       lo = (u32) mac->stats.rx_cong_drops;
+       mac->stats.rx_cong_drops += (u64) (v - lo);
+
+       return &mac->stats;
+}
index 4ae0fed..9f7e1db 100644 (file)
@@ -5,7 +5,7 @@
  *
  *      adopted from sunlance.c by Richard van den Berg
  *
- *      Copyright (C) 2002, 2003, 2005  Maciej W. Rozycki
+ *      Copyright (C) 2002, 2003, 2005, 2006  Maciej W. Rozycki
  *
  *      additional sources:
  *      - PMAD-AA TURBOchannel Ethernet Module Functional Specification,
@@ -44,6 +44,8 @@
  *      v0.010: Fixes for the PMAD mapping of the LANCE buffer and for the
  *              PMAX requirement to only use halfword accesses to the
  *              buffer. macro
+ *
+ *      v0.011: Converted the PMAD to the driver model. macro
  */
 
 #include <linux/crc32.h>
@@ -58,6 +60,7 @@
 #include <linux/spinlock.h>
 #include <linux/stddef.h>
 #include <linux/string.h>
+#include <linux/tc.h>
 #include <linux/types.h>
 
 #include <asm/addrspace.h>
 #include <asm/dec/kn01.h>
 #include <asm/dec/machtype.h>
 #include <asm/dec/system.h>
-#include <asm/dec/tc.h>
 
 static char version[] __devinitdata =
-"declance.c: v0.010 by Linux MIPS DECstation task force\n";
+"declance.c: v0.011 by Linux MIPS DECstation task force\n";
 
 MODULE_AUTHOR("Linux MIPS DECstation task force");
 MODULE_DESCRIPTION("DEC LANCE (DECstation onboard, PMAD-xx) driver");
 MODULE_LICENSE("GPL");
 
+#define __unused __attribute__ ((unused))
+
 /*
  * card types
  */
@@ -246,7 +250,6 @@ struct lance_init_block {
 struct lance_private {
        struct net_device *next;
        int type;
-       int slot;
        int dma_irq;
        volatile struct lance_regs *ll;
 
@@ -288,6 +291,7 @@ struct lance_regs {
 
 int dec_lance_debug = 2;
 
+static struct tc_driver dec_lance_tc_driver;
 static struct net_device *root_lance_dev;
 
 static inline void writereg(volatile unsigned short *regptr, short value)
@@ -1023,7 +1027,7 @@ static void lance_set_multicast_retry(unsigned long _opaque)
        lance_set_multicast(dev);
 }
 
-static int __init dec_lance_init(const int type, const int slot)
+static int __init dec_lance_probe(struct device *bdev, const int type)
 {
        static unsigned version_printed;
        static const char fmt[] = "declance%d";
@@ -1031,6 +1035,7 @@ static int __init dec_lance_init(const int type, const int slot)
        struct net_device *dev;
        struct lance_private *lp;
        volatile struct lance_regs *ll;
+       resource_size_t start = 0, len = 0;
        int i, ret;
        unsigned long esar_base;
        unsigned char *esar;
@@ -1038,14 +1043,18 @@ static int __init dec_lance_init(const int type, const int slot)
        if (dec_lance_debug && version_printed++ == 0)
                printk(version);
 
-       i = 0;
-       dev = root_lance_dev;
-       while (dev) {
-               i++;
-               lp = (struct lance_private *)dev->priv;
-               dev = lp->next;
+       if (bdev)
+               snprintf(name, sizeof(name), "%s", bdev->bus_id);
+       else {
+               i = 0;
+               dev = root_lance_dev;
+               while (dev) {
+                       i++;
+                       lp = (struct lance_private *)dev->priv;
+                       dev = lp->next;
+               }
+               snprintf(name, sizeof(name), fmt, i);
        }
-       snprintf(name, sizeof(name), fmt, i);
 
        dev = alloc_etherdev(sizeof(struct lance_private));
        if (!dev) {
@@ -1063,7 +1072,6 @@ static int __init dec_lance_init(const int type, const int slot)
        spin_lock_init(&lp->lock);
 
        lp->type = type;
-       lp->slot = slot;
        switch (type) {
        case ASIC_LANCE:
                dev->base_addr = CKSEG1ADDR(dec_kn_slot_base + IOASIC_LANCE);
@@ -1110,12 +1118,22 @@ static int __init dec_lance_init(const int type, const int slot)
                break;
 #ifdef CONFIG_TC
        case PMAD_LANCE:
-               claim_tc_card(slot);
+               dev_set_drvdata(bdev, dev);
+
+               start = to_tc_dev(bdev)->resource.start;
+               len = to_tc_dev(bdev)->resource.end - start + 1;
+               if (!request_mem_region(start, len, bdev->bus_id)) {
+                       printk(KERN_ERR
+                              "%s: Unable to reserve MMIO resource\n",
+                              bdev->bus_id);
+                       ret = -EBUSY;
+                       goto err_out_dev;
+               }
 
-               dev->mem_start = CKSEG1ADDR(get_tc_base_addr(slot));
+               dev->mem_start = CKSEG1ADDR(start);
                dev->mem_end = dev->mem_start + 0x100000;
                dev->base_addr = dev->mem_start + 0x100000;
-               dev->irq = get_tc_irq_nr(slot);
+               dev->irq = to_tc_dev(bdev)->interrupt;
                esar_base = dev->mem_start + 0x1c0002;
                lp->dma_irq = -1;
 
@@ -1174,7 +1192,7 @@ static int __init dec_lance_init(const int type, const int slot)
                printk(KERN_ERR "%s: declance_init called with unknown type\n",
                        name);
                ret = -ENODEV;
-               goto err_out_free_dev;
+               goto err_out_dev;
        }
 
        ll = (struct lance_regs *) dev->base_addr;
@@ -1188,7 +1206,7 @@ static int __init dec_lance_init(const int type, const int slot)
                        "%s: Ethernet station address prom not found!\n",
                        name);
                ret = -ENODEV;
-               goto err_out_free_dev;
+               goto err_out_resource;
        }
        /* Check the prom contents */
        for (i = 0; i < 8; i++) {
@@ -1198,7 +1216,7 @@ static int __init dec_lance_init(const int type, const int slot)
                        printk(KERN_ERR "%s: Something is wrong with the "
                                "ethernet station address prom!\n", name);
                        ret = -ENODEV;
-                       goto err_out_free_dev;
+                       goto err_out_resource;
                }
        }
 
@@ -1255,48 +1273,51 @@ static int __init dec_lance_init(const int type, const int slot)
        if (ret) {
                printk(KERN_ERR
                        "%s: Unable to register netdev, aborting.\n", name);
-               goto err_out_free_dev;
+               goto err_out_resource;
        }
 
-       lp->next = root_lance_dev;
-       root_lance_dev = dev;
+       if (!bdev) {
+               lp->next = root_lance_dev;
+               root_lance_dev = dev;
+       }
 
        printk("%s: registered as %s.\n", name, dev->name);
        return 0;
 
-err_out_free_dev:
+err_out_resource:
+       if (bdev)
+               release_mem_region(start, len);
+
+err_out_dev:
        free_netdev(dev);
 
 err_out:
        return ret;
 }
 
+static void __exit dec_lance_remove(struct device *bdev)
+{
+       struct net_device *dev = dev_get_drvdata(bdev);
+       resource_size_t start, len;
+
+       unregister_netdev(dev);
+       start = to_tc_dev(bdev)->resource.start;
+       len = to_tc_dev(bdev)->resource.end - start + 1;
+       release_mem_region(start, len);
+       free_netdev(dev);
+}
 
 /* Find all the lance cards on the system and initialize them */
-static int __init dec_lance_probe(void)
+static int __init dec_lance_platform_probe(void)
 {
        int count = 0;
 
-       /* Scan slots for PMAD-AA cards first. */
-#ifdef CONFIG_TC
-       if (TURBOCHANNEL) {
-               int slot;
-
-               while ((slot = search_tc_card("PMAD-AA")) >= 0) {
-                       if (dec_lance_init(PMAD_LANCE, slot) < 0)
-                               break;
-                       count++;
-               }
-       }
-#endif
-
-       /* Then handle onboard devices. */
        if (dec_interrupt[DEC_IRQ_LANCE] >= 0) {
                if (dec_interrupt[DEC_IRQ_LANCE_MERR] >= 0) {
-                       if (dec_lance_init(ASIC_LANCE, -1) >= 0)
+                       if (dec_lance_probe(NULL, ASIC_LANCE) >= 0)
                                count++;
                } else if (!TURBOCHANNEL) {
-                       if (dec_lance_init(PMAX_LANCE, -1) >= 0)
+                       if (dec_lance_probe(NULL, PMAX_LANCE) >= 0)
                                count++;
                }
        }
@@ -1304,21 +1325,70 @@ static int __init dec_lance_probe(void)
        return (count > 0) ? 0 : -ENODEV;
 }
 
-static void __exit dec_lance_cleanup(void)
+static void __exit dec_lance_platform_remove(void)
 {
        while (root_lance_dev) {
                struct net_device *dev = root_lance_dev;
                struct lance_private *lp = netdev_priv(dev);
 
                unregister_netdev(dev);
-#ifdef CONFIG_TC
-               if (lp->slot >= 0)
-                       release_tc_card(lp->slot);
-#endif
                root_lance_dev = lp->next;
                free_netdev(dev);
        }
 }
 
-module_init(dec_lance_probe);
-module_exit(dec_lance_cleanup);
+#ifdef CONFIG_TC
+static int __init dec_lance_tc_probe(struct device *dev);
+static int __exit dec_lance_tc_remove(struct device *dev);
+
+static const struct tc_device_id dec_lance_tc_table[] = {
+       { "DEC     ", "PMAD-AA " },
+       { }
+};
+MODULE_DEVICE_TABLE(tc, dec_lance_tc_table);
+
+static struct tc_driver dec_lance_tc_driver = {
+       .id_table       = dec_lance_tc_table,
+       .driver         = {
+               .name   = "declance",
+               .bus    = &tc_bus_type,
+               .probe  = dec_lance_tc_probe,
+               .remove = __exit_p(dec_lance_tc_remove),
+       },
+};
+
+static int __init dec_lance_tc_probe(struct device *dev)
+{
+        int status = dec_lance_probe(dev, PMAD_LANCE);
+        if (!status)
+                get_device(dev);
+        return status;
+}
+
+static int __exit dec_lance_tc_remove(struct device *dev)
+{
+        put_device(dev);
+        dec_lance_remove(dev);
+        return 0;
+}
+#endif
+
+static int __init dec_lance_init(void)
+{
+       int status;
+
+       status = tc_register_driver(&dec_lance_tc_driver);
+       if (!status)
+               dec_lance_platform_probe();
+       return status;
+}
+
+static void __exit dec_lance_exit(void)
+{
+       dec_lance_platform_remove();
+       tc_unregister_driver(&dec_lance_tc_driver);
+}
+
+
+module_init(dec_lance_init);
+module_exit(dec_lance_exit);
index f091042..689f158 100644 (file)
 #include <linux/capability.h>
 #include <linux/in.h>
 #include <linux/ip.h>
-#ifdef NETIF_F_TSO6
 #include <linux/ipv6.h>
-#endif
 #include <linux/tcp.h>
 #include <linux/udp.h>
 #include <net/pkt_sched.h>
 #include <linux/list.h>
 #include <linux/reboot.h>
-#ifdef NETIF_F_TSO
 #include <net/checksum.h>
-#endif
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
@@ -257,7 +253,6 @@ struct e1000_adapter {
        spinlock_t tx_queue_lock;
 #endif
        atomic_t irq_sem;
-       unsigned int detect_link;
        unsigned int total_tx_bytes;
        unsigned int total_tx_packets;
        unsigned int total_rx_bytes;
@@ -348,9 +343,7 @@ struct e1000_adapter {
        boolean_t have_msi;
 #endif
        /* to not mess up cache alignment, always add to the bottom */
-#ifdef NETIF_F_TSO
        boolean_t tso_force;
-#endif
        boolean_t smart_power_down;     /* phy smart power down */
        boolean_t quad_port_a;
        unsigned long flags;
index fb96c87..44ebc72 100644 (file)
@@ -338,7 +338,6 @@ e1000_set_tx_csum(struct net_device *netdev, uint32_t data)
        return 0;
 }
 
-#ifdef NETIF_F_TSO
 static int
 e1000_set_tso(struct net_device *netdev, uint32_t data)
 {
@@ -352,18 +351,15 @@ e1000_set_tso(struct net_device *netdev, uint32_t data)
        else
                netdev->features &= ~NETIF_F_TSO;
 
-#ifdef NETIF_F_TSO6
        if (data)
                netdev->features |= NETIF_F_TSO6;
        else
                netdev->features &= ~NETIF_F_TSO6;
-#endif
 
        DPRINTK(PROBE, INFO, "TSO is %s\n", data ? "Enabled" : "Disabled");
        adapter->tso_force = TRUE;
        return 0;
 }
-#endif /* NETIF_F_TSO */
 
 static uint32_t
 e1000_get_msglevel(struct net_device *netdev)
@@ -1971,10 +1967,8 @@ static const struct ethtool_ops e1000_ethtool_ops = {
        .set_tx_csum            = e1000_set_tx_csum,
        .get_sg                 = ethtool_op_get_sg,
        .set_sg                 = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
        .get_tso                = ethtool_op_get_tso,
        .set_tso                = e1000_set_tso,
-#endif
        .self_test_count        = e1000_diag_test_count,
        .self_test              = e1000_diag_test,
        .get_strings            = e1000_get_strings,
index c6259c7..619c892 100644 (file)
@@ -36,7 +36,7 @@ static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
 #else
 #define DRIVERNAPI "-NAPI"
 #endif
-#define DRV_VERSION "7.3.15-k2"DRIVERNAPI
+#define DRV_VERSION "7.3.20-k2"DRIVERNAPI
 char e1000_driver_version[] = DRV_VERSION;
 static char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
 
@@ -990,16 +990,12 @@ e1000_probe(struct pci_dev *pdev,
                        netdev->features &= ~NETIF_F_HW_VLAN_FILTER;
        }
 
-#ifdef NETIF_F_TSO
        if ((adapter->hw.mac_type >= e1000_82544) &&
           (adapter->hw.mac_type != e1000_82547))
                netdev->features |= NETIF_F_TSO;
 
-#ifdef NETIF_F_TSO6
        if (adapter->hw.mac_type > e1000_82547_rev_2)
                netdev->features |= NETIF_F_TSO6;
-#endif
-#endif
        if (pci_using_dac)
                netdev->features |= NETIF_F_HIGHDMA;
 
@@ -2583,15 +2579,22 @@ e1000_watchdog(unsigned long data)
 
        if (link) {
                if (!netif_carrier_ok(netdev)) {
+                       uint32_t ctrl;
                        boolean_t txb2b = 1;
                        e1000_get_speed_and_duplex(&adapter->hw,
                                                   &adapter->link_speed,
                                                   &adapter->link_duplex);
 
-                       DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s\n",
-                              adapter->link_speed,
-                              adapter->link_duplex == FULL_DUPLEX ?
-                              "Full Duplex" : "Half Duplex");
+                       ctrl = E1000_READ_REG(&adapter->hw, CTRL);
+                       DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s, "
+                               "Flow Control: %s\n",
+                               adapter->link_speed,
+                               adapter->link_duplex == FULL_DUPLEX ?
+                               "Full Duplex" : "Half Duplex",
+                               ((ctrl & E1000_CTRL_TFCE) && (ctrl &
+                               E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl &
+                               E1000_CTRL_RFCE) ? "RX" : ((ctrl &
+                               E1000_CTRL_TFCE) ? "TX" : "None" )));
 
                        /* tweak tx_queue_len according to speed/duplex
                         * and adjust the timeout factor */
@@ -2619,7 +2622,6 @@ e1000_watchdog(unsigned long data)
                                E1000_WRITE_REG(&adapter->hw, TARC0, tarc0);
                        }
 
-#ifdef NETIF_F_TSO
                        /* disable TSO for pcie and 10/100 speeds, to avoid
                         * some hardware issues */
                        if (!adapter->tso_force &&
@@ -2630,22 +2632,17 @@ e1000_watchdog(unsigned long data)
                                        DPRINTK(PROBE,INFO,
                                        "10/100 speed: disabling TSO\n");
                                        netdev->features &= ~NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
                                        netdev->features &= ~NETIF_F_TSO6;
-#endif
                                        break;
                                case SPEED_1000:
                                        netdev->features |= NETIF_F_TSO;
-#ifdef NETIF_F_TSO6
                                        netdev->features |= NETIF_F_TSO6;
-#endif
                                        break;
                                default:
                                        /* oops */
                                        break;
                                }
                        }
-#endif
 
                        /* enable transmits in the hardware, need to do this
                         * after setting TARC0 */
@@ -2875,7 +2872,6 @@ static int
 e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
           struct sk_buff *skb)
 {
-#ifdef NETIF_F_TSO
        struct e1000_context_desc *context_desc;
        struct e1000_buffer *buffer_info;
        unsigned int i;
@@ -2904,7 +2900,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
                                                   0);
                        cmd_length = E1000_TXD_CMD_IP;
                        ipcse = skb->h.raw - skb->data - 1;
-#ifdef NETIF_F_TSO6
                } else if (skb->protocol == htons(ETH_P_IPV6)) {
                        skb->nh.ipv6h->payload_len = 0;
                        skb->h.th->check =
@@ -2914,7 +2909,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
                                                 IPPROTO_TCP,
                                                 0);
                        ipcse = 0;
-#endif
                }
                ipcss = skb->nh.raw - skb->data;
                ipcso = (void *)&(skb->nh.iph->check) - (void *)skb->data;
@@ -2947,8 +2941,6 @@ e1000_tso(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
 
                return TRUE;
        }
-#endif
-
        return FALSE;
 }
 
@@ -2968,8 +2960,9 @@ e1000_tx_csum(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
                buffer_info = &tx_ring->buffer_info[i];
                context_desc = E1000_CONTEXT_DESC(*tx_ring, i);
 
+               context_desc->lower_setup.ip_config = 0;
                context_desc->upper_setup.tcp_fields.tucss = css;
-               context_desc->upper_setup.tcp_fields.tucso = css + skb->csum_offset;
+               context_desc->upper_setup.tcp_fields.tucso = css + skb->csum;
                context_desc->upper_setup.tcp_fields.tucse = 0;
                context_desc->tcp_seg_setup.data = 0;
                context_desc->cmd_and_length = cpu_to_le32(E1000_TXD_CMD_DEXT);
@@ -3005,7 +2998,6 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
        while (len) {
                buffer_info = &tx_ring->buffer_info[i];
                size = min(len, max_per_txd);
-#ifdef NETIF_F_TSO
                /* Workaround for Controller erratum --
                 * descriptor for non-tso packet in a linear SKB that follows a
                 * tso gets written back prematurely before the data is fully
@@ -3020,7 +3012,6 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
                 * in TSO mode.  Append 4-byte sentinel desc */
                if (unlikely(mss && !nr_frags && size == len && size > 8))
                        size -= 4;
-#endif
                /* work-around for errata 10 and it applies
                 * to all controllers in PCI-X mode
                 * The fix is to make sure that the first descriptor of a
@@ -3062,12 +3053,10 @@ e1000_tx_map(struct e1000_adapter *adapter, struct e1000_tx_ring *tx_ring,
                while (len) {
                        buffer_info = &tx_ring->buffer_info[i];
                        size = min(len, max_per_txd);
-#ifdef NETIF_F_TSO
                        /* Workaround for premature desc write-backs
                         * in TSO mode.  Append 4-byte sentinel desc */
                        if (unlikely(mss && f == (nr_frags-1) && size == len && size > 8))
                                size -= 4;
-#endif
                        /* Workaround for potential 82544 hang in PCI-X.
                         * Avoid terminating buffers within evenly-aligned
                         * dwords. */
@@ -3292,7 +3281,6 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        if (adapter->hw.mac_type >= e1000_82571)
                max_per_txd = 8192;
 
-#ifdef NETIF_F_TSO
        mss = skb_shinfo(skb)->gso_size;
        /* The controller does a simple calculation to
         * make sure there is enough room in the FIFO before
@@ -3346,16 +3334,10 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        if ((mss) || (skb->ip_summed == CHECKSUM_PARTIAL))
                count++;
        count++;
-#else
-       if (skb->ip_summed == CHECKSUM_PARTIAL)
-               count++;
-#endif
 
-#ifdef NETIF_F_TSO
        /* Controller Erratum workaround */
        if (!skb->data_len && tx_ring->last_tx_tso && !skb_is_gso(skb))
                count++;
-#endif
 
        count += TXD_USE_COUNT(len, max_txd_pwr);
 
@@ -3602,7 +3584,7 @@ e1000_update_stats(struct e1000_adapter *adapter)
         */
        if (adapter->link_speed == 0)
                return;
-       if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
+       if (pci_channel_offline(pdev))
                return;
 
        spin_lock_irqsave(&adapter->stats_lock, flags);
@@ -3765,8 +3747,8 @@ e1000_update_stats(struct e1000_adapter *adapter)
  * @data: pointer to a network interface device structure
  **/
 
-static
-irqreturn_t e1000_intr_msi(int irq, void *data)
+static irqreturn_t
+e1000_intr_msi(int irq, void *data)
 {
        struct net_device *netdev = data;
        struct e1000_adapter *adapter = netdev_priv(netdev);
@@ -3774,49 +3756,27 @@ irqreturn_t e1000_intr_msi(int irq, void *data)
 #ifndef CONFIG_E1000_NAPI
        int i;
 #endif
+       uint32_t icr = E1000_READ_REG(hw, ICR);
 
-       /* this code avoids the read of ICR but has to get 1000 interrupts
-        * at every link change event before it will notice the change */
-       if (++adapter->detect_link >= 1000) {
-               uint32_t icr = E1000_READ_REG(hw, ICR);
 #ifdef CONFIG_E1000_NAPI
-               /* read ICR disables interrupts using IAM, so keep up with our
-                * enable/disable accounting */
-               atomic_inc(&adapter->irq_sem);
+       /* read ICR disables interrupts using IAM, so keep up with our
+        * enable/disable accounting */
+       atomic_inc(&adapter->irq_sem);
 #endif
-               adapter->detect_link = 0;
-               if ((icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) &&
-                   (icr & E1000_ICR_INT_ASSERTED)) {
-                       hw->get_link_status = 1;
-                       /* 80003ES2LAN workaround--
-                       * For packet buffer work-around on link down event;
-                       * disable receives here in the ISR and
-                       * reset adapter in watchdog
-                       */
-                       if (netif_carrier_ok(netdev) &&
-                           (adapter->hw.mac_type == e1000_80003es2lan)) {
-                               /* disable receives */
-                               uint32_t rctl = E1000_READ_REG(hw, RCTL);
-                               E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
-                       }
-                       /* guard against interrupt when we're going down */
-                       if (!test_bit(__E1000_DOWN, &adapter->flags))
-                               mod_timer(&adapter->watchdog_timer,
-                                         jiffies + 1);
+       if (icr & (E1000_ICR_RXSEQ | E1000_ICR_LSC)) {
+               hw->get_link_status = 1;
+               /* 80003ES2LAN workaround-- For packet buffer work-around on
+                * link down event; disable receives here in the ISR and reset
+                * adapter in watchdog */
+               if (netif_carrier_ok(netdev) &&
+                   (adapter->hw.mac_type == e1000_80003es2lan)) {
+                       /* disable receives */
+                       uint32_t rctl = E1000_READ_REG(hw, RCTL);
+                       E1000_WRITE_REG(hw, RCTL, rctl & ~E1000_RCTL_EN);
                }
-       } else {
-               E1000_WRITE_REG(hw, ICR, (0xffffffff & ~(E1000_ICR_RXSEQ |
-                                                        E1000_ICR_LSC)));
-               /* bummer we have to flush here, but things break otherwise as
-                * some event appears to be lost or delayed and throughput
-                * drops.  In almost all tests this flush is un-necessary */
-               E1000_WRITE_FLUSH(hw);
-#ifdef CONFIG_E1000_NAPI
-               /* Interrupt Auto-Mask (IAM)...upon writing ICR, interrupts are
-                * masked.  No need for the IMC write, but it does mean we
-                * should account for it ASAP. */
-               atomic_inc(&adapter->irq_sem);
-#endif
+               /* guard against interrupt when we're going down */
+               if (!test_bit(__E1000_DOWN, &adapter->flags))
+                       mod_timer(&adapter->watchdog_timer, jiffies + 1);
        }
 
 #ifdef CONFIG_E1000_NAPI
@@ -3836,7 +3796,7 @@ irqreturn_t e1000_intr_msi(int irq, void *data)
 
        for (i = 0; i < E1000_MAX_INTR; i++)
                if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) &
-                  !e1000_clean_tx_irq(adapter, adapter->tx_ring)))
+                  e1000_clean_tx_irq(adapter, adapter->tx_ring)))
                        break;
 
        if (likely(adapter->itr_setting & 3))
@@ -3939,7 +3899,7 @@ e1000_intr(int irq, void *data)
 
        for (i = 0; i < E1000_MAX_INTR; i++)
                if (unlikely(!adapter->clean_rx(adapter, adapter->rx_ring) &
-                  !e1000_clean_tx_irq(adapter, adapter->tx_ring)))
+                  e1000_clean_tx_irq(adapter, adapter->tx_ring)))
                        break;
 
        if (likely(adapter->itr_setting & 3))
@@ -3989,7 +3949,7 @@ e1000_clean(struct net_device *poll_dev, int *budget)
        poll_dev->quota -= work_done;
 
        /* If no Tx and not enough Rx work done, exit the polling mode */
-       if ((!tx_cleaned && (work_done == 0)) ||
+       if ((tx_cleaned && (work_done < work_to_do)) ||
           !netif_running(poll_dev)) {
 quit_polling:
                if (likely(adapter->itr_setting & 3))
@@ -4019,7 +3979,7 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
 #ifdef CONFIG_E1000_NAPI
        unsigned int count = 0;
 #endif
-       boolean_t cleaned = FALSE;
+       boolean_t cleaned = TRUE;
        unsigned int total_tx_bytes=0, total_tx_packets=0;
 
        i = tx_ring->next_to_clean;
@@ -4034,10 +3994,13 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
 
                        if (cleaned) {
                                struct sk_buff *skb = buffer_info->skb;
-                               unsigned int segs = skb_shinfo(skb)->gso_segs;
+                               unsigned int segs, bytecount;
+                               segs = skb_shinfo(skb)->gso_segs ?: 1;
+                               /* multiply data chunks by size of headers */
+                               bytecount = ((segs - 1) * skb_headlen(skb)) +
+                                           skb->len;
                                total_tx_packets += segs;
-                               total_tx_packets++;
-                               total_tx_bytes += skb->len;
+                               total_tx_bytes += bytecount;
                        }
                        e1000_unmap_and_free_tx_resource(adapter, buffer_info);
                        tx_desc->upper.data = 0;
@@ -4050,7 +4013,10 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter,
 #ifdef CONFIG_E1000_NAPI
 #define E1000_TX_WEIGHT 64
                /* weight of a sort for tx, to avoid endless transmit cleanup */
-               if (count++ == E1000_TX_WEIGHT) break;
+               if (count++ == E1000_TX_WEIGHT) {
+                       cleaned = FALSE;
+                       break;
+               }
 #endif
        }
 
index 18afc0c..10af742 100644 (file)
@@ -48,8 +48,6 @@ typedef enum {
     TRUE = 1
 } boolean_t;
 
-#define MSGOUT(S, A, B)        printk(KERN_DEBUG S "\n", A, B)
-
 #ifdef DBG
 #define DEBUGOUT(S)            printk(KERN_DEBUG S "\n")
 #define DEBUGOUT1(S, A...)     printk(KERN_DEBUG S "\n", A)
@@ -58,7 +56,7 @@ typedef enum {
 #define DEBUGOUT1(S, A...)
 #endif
 
-#define DEBUGFUNC(F) DEBUGOUT(F)
+#define DEBUGFUNC(F) DEBUGOUT(F "\n")
 #define DEBUGOUT2 DEBUGOUT1
 #define DEBUGOUT3 DEBUGOUT2
 #define DEBUGOUT7 DEBUGOUT3
index cf2a279..f8862e2 100644 (file)
@@ -760,22 +760,13 @@ e1000_check_copper_options(struct e1000_adapter *adapter)
        case SPEED_1000:
                DPRINTK(PROBE, INFO, "1000 Mbps Speed specified without "
                        "Duplex\n");
-               DPRINTK(PROBE, INFO,
-                       "Using Autonegotiation at 1000 Mbps "
-                       "Full Duplex only\n");
-               adapter->hw.autoneg = adapter->fc_autoneg = 1;
-               adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
-               break;
+               goto full_duplex_only;
        case SPEED_1000 + HALF_DUPLEX:
                DPRINTK(PROBE, INFO,
                        "Half Duplex is not supported at 1000 Mbps\n");
-               DPRINTK(PROBE, INFO,
-                       "Using Autonegotiation at 1000 Mbps "
-                       "Full Duplex only\n");
-               adapter->hw.autoneg = adapter->fc_autoneg = 1;
-               adapter->hw.autoneg_advertised = ADVERTISE_1000_FULL;
-               break;
+               /* fall through */
        case SPEED_1000 + FULL_DUPLEX:
+full_duplex_only:
                DPRINTK(PROBE, INFO,
                       "Using Autonegotiation at 1000 Mbps Full Duplex only\n");
                adapter->hw.autoneg = adapter->fc_autoneg = 1;
index 93f2b7a..a363148 100644 (file)
  *     0.57: 14 May 2006: Mac address set in probe/remove and order corrections.
  *     0.58: 30 Oct 2006: Added support for sideband management unit.
  *     0.59: 30 Oct 2006: Added support for recoverable error.
+ *     0.60: 20 Jan 2007: Code optimizations for rings, rx & tx data paths, and stats.
  *
  * Known bugs:
  * We suspect that on some hardware no TX done interrupts are generated.
 #else
 #define DRIVERNAPI
 #endif
-#define FORCEDETH_VERSION              "0.59"
+#define FORCEDETH_VERSION              "0.60"
 #define DRV_NAME                       "forcedeth"
 
 #include <linux/module.h>
 #define DEV_HAS_MSI_X           0x0080  /* device supports MSI-X */
 #define DEV_HAS_POWER_CNTRL     0x0100  /* device supports power savings */
 #define DEV_HAS_PAUSEFRAME_TX   0x0200  /* device supports tx pause frames */
-#define DEV_HAS_STATISTICS      0x0400  /* device supports hw statistics */
-#define DEV_HAS_TEST_EXTENDED   0x0800  /* device supports extended diagnostic test */
-#define DEV_HAS_MGMT_UNIT       0x1000  /* device supports management unit */
+#define DEV_HAS_STATISTICS_V1   0x0400  /* device supports hw statistics version 1 */
+#define DEV_HAS_STATISTICS_V2   0x0800  /* device supports hw statistics version 2 */
+#define DEV_HAS_TEST_EXTENDED   0x1000  /* device supports extended diagnostic test */
+#define DEV_HAS_MGMT_UNIT       0x2000  /* device supports management unit */
 
 enum {
        NvRegIrqStatus = 0x000,
@@ -210,7 +212,7 @@ enum {
  * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
  */
        NvRegPollingInterval = 0x00c,
-#define NVREG_POLL_DEFAULT_THROUGHPUT  970
+#define NVREG_POLL_DEFAULT_THROUGHPUT  970 /* backup tx cleanup if loop max reached */
 #define NVREG_POLL_DEFAULT_CPU 13
        NvRegMSIMap0 = 0x020,
        NvRegMSIMap1 = 0x024,
@@ -304,8 +306,8 @@ enum {
 #define NVREG_TXRXCTL_RESET    0x0010
 #define NVREG_TXRXCTL_RXCHECK  0x0400
 #define NVREG_TXRXCTL_DESC_1   0
-#define NVREG_TXRXCTL_DESC_2   0x02100
-#define NVREG_TXRXCTL_DESC_3   0x02200
+#define NVREG_TXRXCTL_DESC_2   0x002100
+#define NVREG_TXRXCTL_DESC_3   0xc02200
 #define NVREG_TXRXCTL_VLANSTRIP 0x00040
 #define NVREG_TXRXCTL_VLANINS  0x00080
        NvRegTxRingPhysAddrHigh = 0x148,
@@ -487,7 +489,8 @@ union ring_type {
 
 /* Miscelaneous hardware related defines: */
 #define NV_PCI_REGSZ_VER1              0x270
-#define NV_PCI_REGSZ_VER2              0x604
+#define NV_PCI_REGSZ_VER2              0x2d4
+#define NV_PCI_REGSZ_VER3              0x604
 
 /* various timeout delays: all in usec */
 #define NV_TXRX_RESET_DELAY    4
@@ -518,12 +521,6 @@ union ring_type {
 #define TX_RING_MIN            64
 #define RING_MAX_DESC_VER_1    1024
 #define RING_MAX_DESC_VER_2_3  16384
-/*
- * Difference between the get and put pointers for the tx ring.
- * This is used to throttle the amount of data outstanding in the
- * tx ring.
- */
-#define TX_LIMIT_DIFFERENCE    1
 
 /* rx/tx mac addr + type + vlan + align + slack*/
 #define NV_RX_HEADERS          (64)
@@ -611,9 +608,6 @@ static const struct nv_ethtool_str nv_estats_str[] = {
        { "tx_carrier_errors" },
        { "tx_excess_deferral" },
        { "tx_retry_error" },
-       { "tx_deferral" },
-       { "tx_packets" },
-       { "tx_pause" },
        { "rx_frame_error" },
        { "rx_extra_byte" },
        { "rx_late_collision" },
@@ -626,11 +620,17 @@ static const struct nv_ethtool_str nv_estats_str[] = {
        { "rx_unicast" },
        { "rx_multicast" },
        { "rx_broadcast" },
+       { "rx_packets" },
+       { "rx_errors_total" },
+       { "tx_errors_total" },
+
+       /* version 2 stats */
+       { "tx_deferral" },
+       { "tx_packets" },
        { "rx_bytes" },
+       { "tx_pause" },
        { "rx_pause" },
-       { "rx_drop_frame" },
-       { "rx_packets" },
-       { "rx_errors_total" }
+       { "rx_drop_frame" }
 };
 
 struct nv_ethtool_stats {
@@ -643,9 +643,6 @@ struct nv_ethtool_stats {
        u64 tx_carrier_errors;
        u64 tx_excess_deferral;
        u64 tx_retry_error;
-       u64 tx_deferral;
-       u64 tx_packets;
-       u64 tx_pause;
        u64 rx_frame_error;
        u64 rx_extra_byte;
        u64 rx_late_collision;
@@ -658,13 +655,22 @@ struct nv_ethtool_stats {
        u64 rx_unicast;
        u64 rx_multicast;
        u64 rx_broadcast;
+       u64 rx_packets;
+       u64 rx_errors_total;
+       u64 tx_errors_total;
+
+       /* version 2 stats */
+       u64 tx_deferral;
+       u64 tx_packets;
        u64 rx_bytes;
+       u64 tx_pause;
        u64 rx_pause;
        u64 rx_drop_frame;
-       u64 rx_packets;
-       u64 rx_errors_total;
 };
 
+#define NV_DEV_STATISTICS_V2_COUNT (sizeof(struct nv_ethtool_stats)/sizeof(u64))
+#define NV_DEV_STATISTICS_V1_COUNT (NV_DEV_STATISTICS_V2_COUNT - 6)
+
 /* diagnostics */
 #define NV_TEST_COUNT_BASE 3
 #define NV_TEST_COUNT_EXTENDED 4
@@ -691,6 +697,12 @@ static const struct register_test nv_registers_test[] = {
        { 0,0 }
 };
 
+struct nv_skb_map {
+       struct sk_buff *skb;
+       dma_addr_t dma;
+       unsigned int dma_len;
+};
+
 /*
  * SMP locking:
  * All hardware access under dev->priv->lock, except the performance
@@ -741,10 +753,12 @@ struct fe_priv {
        /* rx specific fields.
         * Locking: Within irq hander or disable_irq+spin_lock(&np->lock);
         */
+       union ring_type get_rx, put_rx, first_rx, last_rx;
+       struct nv_skb_map *get_rx_ctx, *put_rx_ctx;
+       struct nv_skb_map *first_rx_ctx, *last_rx_ctx;
+       struct nv_skb_map *rx_skb;
+
        union ring_type rx_ring;
-       unsigned int cur_rx, refill_rx;
-       struct sk_buff **rx_skbuff;
-       dma_addr_t *rx_dma;
        unsigned int rx_buf_sz;
        unsigned int pkt_limit;
        struct timer_list oom_kick;
@@ -761,15 +775,15 @@ struct fe_priv {
        /*
         * tx specific fields.
         */
+       union ring_type get_tx, put_tx, first_tx, last_tx;
+       struct nv_skb_map *get_tx_ctx, *put_tx_ctx;
+       struct nv_skb_map *first_tx_ctx, *last_tx_ctx;
+       struct nv_skb_map *tx_skb;
+
        union ring_type tx_ring;
-       unsigned int next_tx, nic_tx;
-       struct sk_buff **tx_skbuff;
-       dma_addr_t *tx_dma;
-       unsigned int *tx_dma_len;
        u32 tx_flags;
        int tx_ring_size;
-       int tx_limit_start;
-       int tx_limit_stop;
+       int tx_stop;
 
        /* vlan fields */
        struct vlan_group *vlangrp;
@@ -921,16 +935,10 @@ static void free_rings(struct net_device *dev)
                        pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (np->rx_ring_size + np->tx_ring_size),
                                            np->rx_ring.ex, np->ring_addr);
        }
-       if (np->rx_skbuff)
-               kfree(np->rx_skbuff);
-       if (np->rx_dma)
-               kfree(np->rx_dma);
-       if (np->tx_skbuff)
-               kfree(np->tx_skbuff);
-       if (np->tx_dma)
-               kfree(np->tx_dma);
-       if (np->tx_dma_len)
-               kfree(np->tx_dma_len);
+       if (np->rx_skb)
+               kfree(np->rx_skb);
+       if (np->tx_skb)
+               kfree(np->tx_skb);
 }
 
 static int using_multi_irqs(struct net_device *dev)
@@ -1279,6 +1287,61 @@ static void nv_mac_reset(struct net_device *dev)
        pci_push(base);
 }
 
+static void nv_get_hw_stats(struct net_device *dev)
+{
+       struct fe_priv *np = netdev_priv(dev);
+       u8 __iomem *base = get_hwbase(dev);
+
+       np->estats.tx_bytes += readl(base + NvRegTxCnt);
+       np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt);
+       np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt);
+       np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt);
+       np->estats.tx_late_collision += readl(base + NvRegTxLateCol);
+       np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow);
+       np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier);
+       np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef);
+       np->estats.tx_retry_error += readl(base + NvRegTxRetryErr);
+       np->estats.rx_frame_error += readl(base + NvRegRxFrameErr);
+       np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte);
+       np->estats.rx_late_collision += readl(base + NvRegRxLateCol);
+       np->estats.rx_runt += readl(base + NvRegRxRunt);
+       np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong);
+       np->estats.rx_over_errors += readl(base + NvRegRxOverflow);
+       np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr);
+       np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr);
+       np->estats.rx_length_error += readl(base + NvRegRxLenErr);
+       np->estats.rx_unicast += readl(base + NvRegRxUnicast);
+       np->estats.rx_multicast += readl(base + NvRegRxMulticast);
+       np->estats.rx_broadcast += readl(base + NvRegRxBroadcast);
+       np->estats.rx_packets =
+               np->estats.rx_unicast +
+               np->estats.rx_multicast +
+               np->estats.rx_broadcast;
+       np->estats.rx_errors_total =
+               np->estats.rx_crc_errors +
+               np->estats.rx_over_errors +
+               np->estats.rx_frame_error +
+               (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) +
+               np->estats.rx_late_collision +
+               np->estats.rx_runt +
+               np->estats.rx_frame_too_long;
+       np->estats.tx_errors_total =
+               np->estats.tx_late_collision +
+               np->estats.tx_fifo_errors +
+               np->estats.tx_carrier_errors +
+               np->estats.tx_excess_deferral +
+               np->estats.tx_retry_error;
+
+       if (np->driver_data & DEV_HAS_STATISTICS_V2) {
+               np->estats.tx_deferral += readl(base + NvRegTxDef);
+               np->estats.tx_packets += readl(base + NvRegTxFrame);
+               np->estats.rx_bytes += readl(base + NvRegRxCnt);
+               np->estats.tx_pause += readl(base + NvRegTxPause);
+               np->estats.rx_pause += readl(base + NvRegRxPause);
+               np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame);
+       }
+}
+
 /*
  * nv_get_stats: dev->get_stats function
  * Get latest stats value from the nic.
@@ -1289,10 +1352,19 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
 
-       /* It seems that the nic always generates interrupts and doesn't
-        * accumulate errors internally. Thus the current values in np->stats
-        * are already up to date.
-        */
+       /* If the nic supports hw counters then retrieve latest values */
+       if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2)) {
+               nv_get_hw_stats(dev);
+
+               /* copy to net_device stats */
+               np->stats.tx_bytes = np->estats.tx_bytes;
+               np->stats.tx_fifo_errors = np->estats.tx_fifo_errors;
+               np->stats.tx_carrier_errors = np->estats.tx_carrier_errors;
+               np->stats.rx_crc_errors = np->estats.rx_crc_errors;
+               np->stats.rx_over_errors = np->estats.rx_over_errors;
+               np->stats.rx_errors = np->estats.rx_errors_total;
+               np->stats.tx_errors = np->estats.tx_errors_total;
+       }
        return &np->stats;
 }
 
@@ -1304,43 +1376,63 @@ static struct net_device_stats *nv_get_stats(struct net_device *dev)
 static int nv_alloc_rx(struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
-       unsigned int refill_rx = np->refill_rx;
-       int nr;
-
-       while (np->cur_rx != refill_rx) {
-               struct sk_buff *skb;
-
-               nr = refill_rx % np->rx_ring_size;
-               if (np->rx_skbuff[nr] == NULL) {
+       struct ring_desc* less_rx;
 
-                       skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
-                       if (!skb)
-                               break;
+       less_rx = np->get_rx.orig;
+       if (less_rx-- == np->first_rx.orig)
+               less_rx = np->last_rx.orig;
 
+       while (np->put_rx.orig != less_rx) {
+               struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
+               if (skb) {
                        skb->dev = dev;
-                       np->rx_skbuff[nr] = skb;
+                       np->put_rx_ctx->skb = skb;
+                       np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
+                                                            skb->end-skb->data, PCI_DMA_FROMDEVICE);
+                       np->put_rx_ctx->dma_len = skb->end-skb->data;
+                       np->put_rx.orig->buf = cpu_to_le32(np->put_rx_ctx->dma);
+                       wmb();
+                       np->put_rx.orig->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+                       if (unlikely(np->put_rx.orig++ == np->last_rx.orig))
+                               np->put_rx.orig = np->first_rx.orig;
+                       if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
+                               np->put_rx_ctx = np->first_rx_ctx;
                } else {
-                       skb = np->rx_skbuff[nr];
+                       return 1;
                }
-               np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data,
-                                       skb->end-skb->data, PCI_DMA_FROMDEVICE);
-               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-                       np->rx_ring.orig[nr].buf = cpu_to_le32(np->rx_dma[nr]);
+       }
+       return 0;
+}
+
+static int nv_alloc_rx_optimized(struct net_device *dev)
+{
+       struct fe_priv *np = netdev_priv(dev);
+       struct ring_desc_ex* less_rx;
+
+       less_rx = np->get_rx.ex;
+       if (less_rx-- == np->first_rx.ex)
+               less_rx = np->last_rx.ex;
+
+       while (np->put_rx.ex != less_rx) {
+               struct sk_buff *skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD);
+               if (skb) {
+                       skb->dev = dev;
+                       np->put_rx_ctx->skb = skb;
+                       np->put_rx_ctx->dma = pci_map_single(np->pci_dev, skb->data,
+                                                            skb->end-skb->data, PCI_DMA_FROMDEVICE);
+                       np->put_rx_ctx->dma_len = skb->end-skb->data;
+                       np->put_rx.ex->bufhigh = cpu_to_le64(np->put_rx_ctx->dma) >> 32;
+                       np->put_rx.ex->buflow = cpu_to_le64(np->put_rx_ctx->dma) & 0x0FFFFFFFF;
                        wmb();
-                       np->rx_ring.orig[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL);
+                       np->put_rx.ex->flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+                       if (unlikely(np->put_rx.ex++ == np->last_rx.ex))
+                               np->put_rx.ex = np->first_rx.ex;
+                       if (unlikely(np->put_rx_ctx++ == np->last_rx_ctx))
+                               np->put_rx_ctx = np->first_rx_ctx;
                } else {
-                       np->rx_ring.ex[nr].bufhigh = cpu_to_le64(np->rx_dma[nr]) >> 32;
-                       np->rx_ring.ex[nr].buflow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF;
-                       wmb();
-                       np->rx_ring.ex[nr].flaglen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL);
+                       return 1;
                }
-               dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n",
-                                       dev->name, refill_rx);
-               refill_rx++;
        }
-       np->refill_rx = refill_rx;
-       if (np->cur_rx - refill_rx == np->rx_ring_size)
-               return 1;
        return 0;
 }
 
@@ -1358,6 +1450,7 @@ static void nv_do_rx_refill(unsigned long data)
 {
        struct net_device *dev = (struct net_device *) data;
        struct fe_priv *np = netdev_priv(dev);
+       int retcode;
 
        if (!using_multi_irqs(dev)) {
                if (np->msi_flags & NV_MSI_X_ENABLED)
@@ -1367,7 +1460,11 @@ static void nv_do_rx_refill(unsigned long data)
        } else {
                disable_irq(np->msi_x_entry[NV_MSI_X_VECTOR_RX].vector);
        }
-       if (nv_alloc_rx(dev)) {
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               retcode = nv_alloc_rx(dev);
+       else
+               retcode = nv_alloc_rx_optimized(dev);
+       if (retcode) {
                spin_lock_irq(&np->lock);
                if (!np->in_shutdown)
                        mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
@@ -1388,56 +1485,81 @@ static void nv_init_rx(struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
        int i;
+       np->get_rx = np->put_rx = np->first_rx = np->rx_ring;
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               np->last_rx.orig = &np->rx_ring.orig[np->rx_ring_size-1];
+       else
+               np->last_rx.ex = &np->rx_ring.ex[np->rx_ring_size-1];
+       np->get_rx_ctx = np->put_rx_ctx = np->first_rx_ctx = np->rx_skb;
+       np->last_rx_ctx = &np->rx_skb[np->rx_ring_size-1];
 
-       np->cur_rx = np->rx_ring_size;
-       np->refill_rx = 0;
-       for (i = 0; i < np->rx_ring_size; i++)
-               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+       for (i = 0; i < np->rx_ring_size; i++) {
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
                        np->rx_ring.orig[i].flaglen = 0;
-               else
+                       np->rx_ring.orig[i].buf = 0;
+               } else {
                        np->rx_ring.ex[i].flaglen = 0;
+                       np->rx_ring.ex[i].txvlan = 0;
+                       np->rx_ring.ex[i].bufhigh = 0;
+                       np->rx_ring.ex[i].buflow = 0;
+               }
+               np->rx_skb[i].skb = NULL;
+               np->rx_skb[i].dma = 0;
+       }
 }
 
 static void nv_init_tx(struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
        int i;
+       np->get_tx = np->put_tx = np->first_tx = np->tx_ring;
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               np->last_tx.orig = &np->tx_ring.orig[np->tx_ring_size-1];
+       else
+               np->last_tx.ex = &np->tx_ring.ex[np->tx_ring_size-1];
+       np->get_tx_ctx = np->put_tx_ctx = np->first_tx_ctx = np->tx_skb;
+       np->last_tx_ctx = &np->tx_skb[np->tx_ring_size-1];
 
-       np->next_tx = np->nic_tx = 0;
        for (i = 0; i < np->tx_ring_size; i++) {
-               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
                        np->tx_ring.orig[i].flaglen = 0;
-               else
+                       np->tx_ring.orig[i].buf = 0;
+               } else {
                        np->tx_ring.ex[i].flaglen = 0;
-               np->tx_skbuff[i] = NULL;
-               np->tx_dma[i] = 0;
+                       np->tx_ring.ex[i].txvlan = 0;
+                       np->tx_ring.ex[i].bufhigh = 0;
+                       np->tx_ring.ex[i].buflow = 0;
+               }
+               np->tx_skb[i].skb = NULL;
+               np->tx_skb[i].dma = 0;
        }
 }
 
 static int nv_init_ring(struct net_device *dev)
 {
+       struct fe_priv *np = netdev_priv(dev);
+
        nv_init_tx(dev);
        nv_init_rx(dev);
-       return nv_alloc_rx(dev);
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               return nv_alloc_rx(dev);
+       else
+               return nv_alloc_rx_optimized(dev);
 }
 
-static int nv_release_txskb(struct net_device *dev, unsigned int skbnr)
+static int nv_release_txskb(struct net_device *dev, struct nv_skb_map* tx_skb)
 {
        struct fe_priv *np = netdev_priv(dev);
 
-       dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n",
-               dev->name, skbnr);
-
-       if (np->tx_dma[skbnr]) {
-               pci_unmap_page(np->pci_dev, np->tx_dma[skbnr],
-                              np->tx_dma_len[skbnr],
+       if (tx_skb->dma) {
+               pci_unmap_page(np->pci_dev, tx_skb->dma,
+                              tx_skb->dma_len,
                               PCI_DMA_TODEVICE);
-               np->tx_dma[skbnr] = 0;
+               tx_skb->dma = 0;
        }
-
-       if (np->tx_skbuff[skbnr]) {
-               dev_kfree_skb_any(np->tx_skbuff[skbnr]);
-               np->tx_skbuff[skbnr] = NULL;
+       if (tx_skb->skb) {
+               dev_kfree_skb_any(tx_skb->skb);
+               tx_skb->skb = NULL;
                return 1;
        } else {
                return 0;
@@ -1450,11 +1572,16 @@ static void nv_drain_tx(struct net_device *dev)
        unsigned int i;
 
        for (i = 0; i < np->tx_ring_size; i++) {
-               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
                        np->tx_ring.orig[i].flaglen = 0;
-               else
+                       np->tx_ring.orig[i].buf = 0;
+               } else {
                        np->tx_ring.ex[i].flaglen = 0;
-               if (nv_release_txskb(dev, i))
+                       np->tx_ring.ex[i].txvlan = 0;
+                       np->tx_ring.ex[i].bufhigh = 0;
+                       np->tx_ring.ex[i].buflow = 0;
+               }
+               if (nv_release_txskb(dev, &np->tx_skb[i]))
                        np->stats.tx_dropped++;
        }
 }
@@ -1463,18 +1590,24 @@ static void nv_drain_rx(struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
        int i;
+
        for (i = 0; i < np->rx_ring_size; i++) {
-               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
                        np->rx_ring.orig[i].flaglen = 0;
-               else
+                       np->rx_ring.orig[i].buf = 0;
+               } else {
                        np->rx_ring.ex[i].flaglen = 0;
+                       np->rx_ring.ex[i].txvlan = 0;
+                       np->rx_ring.ex[i].bufhigh = 0;
+                       np->rx_ring.ex[i].buflow = 0;
+               }
                wmb();
-               if (np->rx_skbuff[i]) {
-                       pci_unmap_single(np->pci_dev, np->rx_dma[i],
-                                               np->rx_skbuff[i]->end-np->rx_skbuff[i]->data,
+               if (np->rx_skb[i].skb) {
+                       pci_unmap_single(np->pci_dev, np->rx_skb[i].dma,
+                                               np->rx_skb[i].skb->end-np->rx_skb[i].skb->data,
                                                PCI_DMA_FROMDEVICE);
-                       dev_kfree_skb(np->rx_skbuff[i]);
-                       np->rx_skbuff[i] = NULL;
+                       dev_kfree_skb(np->rx_skb[i].skb);
+                       np->rx_skb[i].skb = NULL;
                }
        }
 }
@@ -1485,6 +1618,11 @@ static void drain_ring(struct net_device *dev)
        nv_drain_rx(dev);
 }
 
+static inline u32 nv_get_empty_tx_slots(struct fe_priv *np)
+{
+       return (u32)(np->tx_ring_size - ((np->tx_ring_size + (np->put_tx_ctx - np->get_tx_ctx)) % np->tx_ring_size));
+}
+
 /*
  * nv_start_xmit: dev->hard_start_xmit function
  * Called with netif_tx_lock held.
@@ -1495,14 +1633,16 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
        u32 tx_flags = 0;
        u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET);
        unsigned int fragments = skb_shinfo(skb)->nr_frags;
-       unsigned int nr = (np->next_tx - 1) % np->tx_ring_size;
-       unsigned int start_nr = np->next_tx % np->tx_ring_size;
        unsigned int i;
        u32 offset = 0;
        u32 bcnt;
        u32 size = skb->len-skb->data_len;
        u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
-       u32 tx_flags_vlan = 0;
+       u32 empty_slots;
+       struct ring_desc* put_tx;
+       struct ring_desc* start_tx;
+       struct ring_desc* prev_tx;
+       struct nv_skb_map* prev_tx_ctx;
 
        /* add fragments to entries count */
        for (i = 0; i < fragments; i++) {
@@ -1510,34 +1650,35 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                           ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
        }
 
-       spin_lock_irq(&np->lock);
-
-       if ((np->next_tx - np->nic_tx + entries - 1) > np->tx_limit_stop) {
-               spin_unlock_irq(&np->lock);
+       empty_slots = nv_get_empty_tx_slots(np);
+       if (unlikely(empty_slots <= entries)) {
+               spin_lock_irq(&np->lock);
                netif_stop_queue(dev);
+               np->tx_stop = 1;
+               spin_unlock_irq(&np->lock);
                return NETDEV_TX_BUSY;
        }
 
+       start_tx = put_tx = np->put_tx.orig;
+
        /* setup the header buffer */
        do {
+               prev_tx = put_tx;
+               prev_tx_ctx = np->put_tx_ctx;
                bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
-               nr = (nr + 1) % np->tx_ring_size;
-
-               np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+               np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
                                                PCI_DMA_TODEVICE);
-               np->tx_dma_len[nr] = bcnt;
+               np->put_tx_ctx->dma_len = bcnt;
+               put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
+               put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
 
-               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-                       np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
-                       np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
-               } else {
-                       np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
-                       np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-                       np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
-               }
                tx_flags = np->tx_flags;
                offset += bcnt;
                size -= bcnt;
+               if (unlikely(put_tx++ == np->last_tx.orig))
+                       put_tx = np->first_tx.orig;
+               if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+                       np->put_tx_ctx = np->first_tx_ctx;
        } while (size);
 
        /* setup the fragments */
@@ -1547,58 +1688,174 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                offset = 0;
 
                do {
+                       prev_tx = put_tx;
+                       prev_tx_ctx = np->put_tx_ctx;
                        bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
-                       nr = (nr + 1) % np->tx_ring_size;
+                       np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+                                                          PCI_DMA_TODEVICE);
+                       np->put_tx_ctx->dma_len = bcnt;
+                       put_tx->buf = cpu_to_le32(np->put_tx_ctx->dma);
+                       put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
 
-                       np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
-                                                     PCI_DMA_TODEVICE);
-                       np->tx_dma_len[nr] = bcnt;
-
-                       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-                               np->tx_ring.orig[nr].buf = cpu_to_le32(np->tx_dma[nr]);
-                               np->tx_ring.orig[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
-                       } else {
-                               np->tx_ring.ex[nr].bufhigh = cpu_to_le64(np->tx_dma[nr]) >> 32;
-                               np->tx_ring.ex[nr].buflow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF;
-                               np->tx_ring.ex[nr].flaglen = cpu_to_le32((bcnt-1) | tx_flags);
-                       }
                        offset += bcnt;
                        size -= bcnt;
+                       if (unlikely(put_tx++ == np->last_tx.orig))
+                               put_tx = np->first_tx.orig;
+                       if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+                               np->put_tx_ctx = np->first_tx_ctx;
                } while (size);
        }
 
        /* set last fragment flag  */
-       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-               np->tx_ring.orig[nr].flaglen |= cpu_to_le32(tx_flags_extra);
-       } else {
-               np->tx_ring.ex[nr].flaglen |= cpu_to_le32(tx_flags_extra);
+       prev_tx->flaglen |= cpu_to_le32(tx_flags_extra);
+
+       /* save skb in this slot's context area */
+       prev_tx_ctx->skb = skb;
+
+       if (skb_is_gso(skb))
+               tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
+       else
+               tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
+                        NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
+
+       spin_lock_irq(&np->lock);
+
+       /* set tx flags */
+       start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+       np->put_tx.orig = put_tx;
+
+       spin_unlock_irq(&np->lock);
+
+       dprintk(KERN_DEBUG "%s: nv_start_xmit: entries %d queued for transmission. tx_flags_extra: %x\n",
+               dev->name, entries, tx_flags_extra);
+       {
+               int j;
+               for (j=0; j<64; j++) {
+                       if ((j%16) == 0)
+                               dprintk("\n%03x:", j);
+                       dprintk(" %02x", ((unsigned char*)skb->data)[j]);
+               }
+               dprintk("\n");
        }
 
-       np->tx_skbuff[nr] = skb;
+       dev->trans_start = jiffies;
+       writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
+       return NETDEV_TX_OK;
+}
+
+static int nv_start_xmit_optimized(struct sk_buff *skb, struct net_device *dev)
+{
+       struct fe_priv *np = netdev_priv(dev);
+       u32 tx_flags = 0;
+       u32 tx_flags_extra;
+       unsigned int fragments = skb_shinfo(skb)->nr_frags;
+       unsigned int i;
+       u32 offset = 0;
+       u32 bcnt;
+       u32 size = skb->len-skb->data_len;
+       u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+       u32 empty_slots;
+       struct ring_desc_ex* put_tx;
+       struct ring_desc_ex* start_tx;
+       struct ring_desc_ex* prev_tx;
+       struct nv_skb_map* prev_tx_ctx;
+
+       /* add fragments to entries count */
+       for (i = 0; i < fragments; i++) {
+               entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) +
+                          ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0);
+       }
+
+       empty_slots = nv_get_empty_tx_slots(np);
+       if (unlikely(empty_slots <= entries)) {
+               spin_lock_irq(&np->lock);
+               netif_stop_queue(dev);
+               np->tx_stop = 1;
+               spin_unlock_irq(&np->lock);
+               return NETDEV_TX_BUSY;
+       }
+
+       start_tx = put_tx = np->put_tx.ex;
+
+       /* setup the header buffer */
+       do {
+               prev_tx = put_tx;
+               prev_tx_ctx = np->put_tx_ctx;
+               bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+               np->put_tx_ctx->dma = pci_map_single(np->pci_dev, skb->data + offset, bcnt,
+                                               PCI_DMA_TODEVICE);
+               np->put_tx_ctx->dma_len = bcnt;
+               put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
+               put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
+               put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+
+               tx_flags = NV_TX2_VALID;
+               offset += bcnt;
+               size -= bcnt;
+               if (unlikely(put_tx++ == np->last_tx.ex))
+                       put_tx = np->first_tx.ex;
+               if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+                       np->put_tx_ctx = np->first_tx_ctx;
+       } while (size);
+
+       /* setup the fragments */
+       for (i = 0; i < fragments; i++) {
+               skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+               u32 size = frag->size;
+               offset = 0;
+
+               do {
+                       prev_tx = put_tx;
+                       prev_tx_ctx = np->put_tx_ctx;
+                       bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size;
+                       np->put_tx_ctx->dma = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt,
+                                                          PCI_DMA_TODEVICE);
+                       np->put_tx_ctx->dma_len = bcnt;
+                       put_tx->bufhigh = cpu_to_le64(np->put_tx_ctx->dma) >> 32;
+                       put_tx->buflow = cpu_to_le64(np->put_tx_ctx->dma) & 0x0FFFFFFFF;
+                       put_tx->flaglen = cpu_to_le32((bcnt-1) | tx_flags);
+
+                       offset += bcnt;
+                       size -= bcnt;
+                       if (unlikely(put_tx++ == np->last_tx.ex))
+                               put_tx = np->first_tx.ex;
+                       if (unlikely(np->put_tx_ctx++ == np->last_tx_ctx))
+                               np->put_tx_ctx = np->first_tx_ctx;
+               } while (size);
+       }
+
+       /* set last fragment flag  */
+       prev_tx->flaglen |= cpu_to_le32(NV_TX2_LASTPACKET);
+
+       /* save skb in this slot's context area */
+       prev_tx_ctx->skb = skb;
 
-#ifdef NETIF_F_TSO
        if (skb_is_gso(skb))
                tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->gso_size << NV_TX2_TSO_SHIFT);
        else
-#endif
-       tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
+               tx_flags_extra = skb->ip_summed == CHECKSUM_PARTIAL ?
                         NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
 
        /* vlan tag */
-       if (np->vlangrp && vlan_tx_tag_present(skb)) {
-               tx_flags_vlan = NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb);
+       if (likely(!np->vlangrp)) {
+               start_tx->txvlan = 0;
+       } else {
+               if (vlan_tx_tag_present(skb))
+                       start_tx->txvlan = cpu_to_le32(NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb));
+               else
+                       start_tx->txvlan = 0;
        }
 
+       spin_lock_irq(&np->lock);
+
        /* set tx flags */
-       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-               np->tx_ring.orig[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
-       } else {
-               np->tx_ring.ex[start_nr].txvlan = cpu_to_le32(tx_flags_vlan);
-               np->tx_ring.ex[start_nr].flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
-       }
+       start_tx->flaglen |= cpu_to_le32(tx_flags | tx_flags_extra);
+       np->put_tx.ex = put_tx;
+
+       spin_unlock_irq(&np->lock);
 
-       dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n",
-               dev->name, np->next_tx, entries, tx_flags_extra);
+       dprintk(KERN_DEBUG "%s: nv_start_xmit_optimized: entries %d queued for transmission. tx_flags_extra: %x\n",
+               dev->name, entries, tx_flags_extra);
        {
                int j;
                for (j=0; j<64; j++) {
@@ -1609,12 +1866,8 @@ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev)
                dprintk("\n");
        }
 
-       np->next_tx += entries;
-
        dev->trans_start = jiffies;
-       spin_unlock_irq(&np->lock);
        writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl);
-       pci_push(get_hwbase(dev));
        return NETDEV_TX_OK;
 }
 
@@ -1627,26 +1880,22 @@ static void nv_tx_done(struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
        u32 flags;
-       unsigned int i;
-       struct sk_buff *skb;
+       struct ring_desc* orig_get_tx = np->get_tx.orig;
 
-       while (np->nic_tx != np->next_tx) {
-               i = np->nic_tx % np->tx_ring_size;
+       while ((np->get_tx.orig != np->put_tx.orig) &&
+              !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID)) {
 
-               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
-                       flags = le32_to_cpu(np->tx_ring.orig[i].flaglen);
-               else
-                       flags = le32_to_cpu(np->tx_ring.ex[i].flaglen);
+               dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n",
+                                       dev->name, flags);
+
+               pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma,
+                              np->get_tx_ctx->dma_len,
+                              PCI_DMA_TODEVICE);
+               np->get_tx_ctx->dma = 0;
 
-               dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, flags 0x%x.\n",
-                                       dev->name, np->nic_tx, flags);
-               if (flags & NV_TX_VALID)
-                       break;
                if (np->desc_ver == DESC_VER_1) {
                        if (flags & NV_TX_LASTPACKET) {
-                               skb = np->tx_skbuff[i];
-                               if (flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION|
-                                            NV_TX_UNDERFLOW|NV_TX_ERROR)) {
+                               if (flags & NV_TX_ERROR) {
                                        if (flags & NV_TX_UNDERFLOW)
                                                np->stats.tx_fifo_errors++;
                                        if (flags & NV_TX_CARRIERLOST)
@@ -1654,14 +1903,14 @@ static void nv_tx_done(struct net_device *dev)
                                        np->stats.tx_errors++;
                                } else {
                                        np->stats.tx_packets++;
-                                       np->stats.tx_bytes += skb->len;
+                                       np->stats.tx_bytes += np->get_tx_ctx->skb->len;
                                }
+                               dev_kfree_skb_any(np->get_tx_ctx->skb);
+                               np->get_tx_ctx->skb = NULL;
                        }
                } else {
                        if (flags & NV_TX2_LASTPACKET) {
-                               skb = np->tx_skbuff[i];
-                               if (flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION|
-                                            NV_TX2_UNDERFLOW|NV_TX2_ERROR)) {
+                               if (flags & NV_TX2_ERROR) {
                                        if (flags & NV_TX2_UNDERFLOW)
                                                np->stats.tx_fifo_errors++;
                                        if (flags & NV_TX2_CARRIERLOST)
@@ -1669,15 +1918,56 @@ static void nv_tx_done(struct net_device *dev)
                                        np->stats.tx_errors++;
                                } else {
                                        np->stats.tx_packets++;
-                                       np->stats.tx_bytes += skb->len;
+                                       np->stats.tx_bytes += np->get_tx_ctx->skb->len;
                                }
+                               dev_kfree_skb_any(np->get_tx_ctx->skb);
+                               np->get_tx_ctx->skb = NULL;
                        }
                }
-               nv_release_txskb(dev, i);
-               np->nic_tx++;
+               if (unlikely(np->get_tx.orig++ == np->last_tx.orig))
+                       np->get_tx.orig = np->first_tx.orig;
+               if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
+                       np->get_tx_ctx = np->first_tx_ctx;
+       }
+       if (unlikely((np->tx_stop == 1) && (np->get_tx.orig != orig_get_tx))) {
+               np->tx_stop = 0;
+               netif_wake_queue(dev);
+       }
+}
+
+static void nv_tx_done_optimized(struct net_device *dev, int limit)
+{
+       struct fe_priv *np = netdev_priv(dev);
+       u32 flags;
+       struct ring_desc_ex* orig_get_tx = np->get_tx.ex;
+
+       while ((np->get_tx.ex != np->put_tx.ex) &&
+              !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) &&
+              (limit-- > 0)) {
+
+               dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n",
+                                       dev->name, flags);
+
+               pci_unmap_page(np->pci_dev, np->get_tx_ctx->dma,
+                              np->get_tx_ctx->dma_len,
+                              PCI_DMA_TODEVICE);
+               np->get_tx_ctx->dma = 0;
+
+               if (flags & NV_TX2_LASTPACKET) {
+                       if (!(flags & NV_TX2_ERROR))
+                               np->stats.tx_packets++;
+                       dev_kfree_skb_any(np->get_tx_ctx->skb);
+                       np->get_tx_ctx->skb = NULL;
+               }
+               if (unlikely(np->get_tx.ex++ == np->last_tx.ex))
+                       np->get_tx.ex = np->first_tx.ex;
+               if (unlikely(np->get_tx_ctx++ == np->last_tx_ctx))
+                       np->get_tx_ctx = np->first_tx_ctx;
        }
-       if (np->next_tx - np->nic_tx < np->tx_limit_start)
+       if (unlikely((np->tx_stop == 1) && (np->get_tx.ex != orig_get_tx))) {
+               np->tx_stop = 0;
                netif_wake_queue(dev);
+       }
 }
 
 /*
@@ -1700,9 +1990,8 @@ static void nv_tx_timeout(struct net_device *dev)
        {
                int i;
 
-               printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n",
-                               dev->name, (unsigned long)np->ring_addr,
-                               np->next_tx, np->nic_tx);
+               printk(KERN_INFO "%s: Ring at %lx\n",
+                      dev->name, (unsigned long)np->ring_addr);
                printk(KERN_INFO "%s: Dumping tx registers\n", dev->name);
                for (i=0;i<=np->register_size;i+= 32) {
                        printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n",
@@ -1750,13 +2039,16 @@ static void nv_tx_timeout(struct net_device *dev)
        nv_stop_tx(dev);
 
        /* 2) check that the packets were not sent already: */
-       nv_tx_done(dev);
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               nv_tx_done(dev);
+       else
+               nv_tx_done_optimized(dev, np->tx_ring_size);
 
        /* 3) if there are dead entries: clear everything */
-       if (np->next_tx != np->nic_tx) {
+       if (np->get_tx_ctx != np->put_tx_ctx) {
                printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
                nv_drain_tx(dev);
-               np->next_tx = np->nic_tx = 0;
+               nv_init_tx(dev);
                setup_hw_rings(dev, NV_SETUP_TX_RING);
                netif_wake_queue(dev);
        }
@@ -1813,50 +2105,175 @@ static int nv_getlen(struct net_device *dev, void *packet, int datalen)
                                        dev->name);
                        return -1;
                }
-               dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
-                               dev->name, datalen);
-               return datalen;
+               dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n",
+                               dev->name, datalen);
+               return datalen;
+       }
+}
+
+static int nv_rx_process(struct net_device *dev, int limit)
+{
+       struct fe_priv *np = netdev_priv(dev);
+       u32 flags;
+       u32 rx_processed_cnt = 0;
+       struct sk_buff *skb;
+       int len;
+
+       while((np->get_rx.orig != np->put_rx.orig) &&
+             !((flags = le32_to_cpu(np->get_rx.orig->flaglen)) & NV_RX_AVAIL) &&
+               (rx_processed_cnt++ < limit)) {
+
+               dprintk(KERN_DEBUG "%s: nv_rx_process: flags 0x%x.\n",
+                                       dev->name, flags);
+
+               /*
+                * the packet is for us - immediately tear down the pci mapping.
+                * TODO: check if a prefetch of the first cacheline improves
+                * the performance.
+                */
+               pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma,
+                               np->get_rx_ctx->dma_len,
+                               PCI_DMA_FROMDEVICE);
+               skb = np->get_rx_ctx->skb;
+               np->get_rx_ctx->skb = NULL;
+
+               {
+                       int j;
+                       dprintk(KERN_DEBUG "Dumping packet (flags 0x%x).",flags);
+                       for (j=0; j<64; j++) {
+                               if ((j%16) == 0)
+                                       dprintk("\n%03x:", j);
+                               dprintk(" %02x", ((unsigned char*)skb->data)[j]);
+                       }
+                       dprintk("\n");
+               }
+               /* look at what we actually got: */
+               if (np->desc_ver == DESC_VER_1) {
+                       if (likely(flags & NV_RX_DESCRIPTORVALID)) {
+                               len = flags & LEN_MASK_V1;
+                               if (unlikely(flags & NV_RX_ERROR)) {
+                                       if (flags & NV_RX_ERROR4) {
+                                               len = nv_getlen(dev, skb->data, len);
+                                               if (len < 0) {
+                                                       np->stats.rx_errors++;
+                                                       dev_kfree_skb(skb);
+                                                       goto next_pkt;
+                                               }
+                                       }
+                                       /* framing errors are soft errors */
+                                       else if (flags & NV_RX_FRAMINGERR) {
+                                               if (flags & NV_RX_SUBSTRACT1) {
+                                                       len--;
+                                               }
+                                       }
+                                       /* the rest are hard errors */
+                                       else {
+                                               if (flags & NV_RX_MISSEDFRAME)
+                                                       np->stats.rx_missed_errors++;
+                                               if (flags & NV_RX_CRCERR)
+                                                       np->stats.rx_crc_errors++;
+                                               if (flags & NV_RX_OVERFLOW)
+                                                       np->stats.rx_over_errors++;
+                                               np->stats.rx_errors++;
+                                               dev_kfree_skb(skb);
+                                               goto next_pkt;
+                                       }
+                               }
+                       } else {
+                               dev_kfree_skb(skb);
+                               goto next_pkt;
+                       }
+               } else {
+                       if (likely(flags & NV_RX2_DESCRIPTORVALID)) {
+                               len = flags & LEN_MASK_V2;
+                               if (unlikely(flags & NV_RX2_ERROR)) {
+                                       if (flags & NV_RX2_ERROR4) {
+                                               len = nv_getlen(dev, skb->data, len);
+                                               if (len < 0) {
+                                                       np->stats.rx_errors++;
+                                                       dev_kfree_skb(skb);
+                                                       goto next_pkt;
+                                               }
+                                       }
+                                       /* framing errors are soft errors */
+                                       else if (flags & NV_RX2_FRAMINGERR) {
+                                               if (flags & NV_RX2_SUBSTRACT1) {
+                                                       len--;
+                                               }
+                                       }
+                                       /* the rest are hard errors */
+                                       else {
+                                               if (flags & NV_RX2_CRCERR)
+                                                       np->stats.rx_crc_errors++;
+                                               if (flags & NV_RX2_OVERFLOW)
+                                                       np->stats.rx_over_errors++;
+                                               np->stats.rx_errors++;
+                                               dev_kfree_skb(skb);
+                                               goto next_pkt;
+                                       }
+                               }
+                               if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+                                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+                               } else {
+                                       if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
+                                           (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
+                                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+                                       }
+                               }
+                       } else {
+                               dev_kfree_skb(skb);
+                               goto next_pkt;
+                       }
+               }
+               /* got a valid packet - forward it to the network core */
+               skb_put(skb, len);
+               skb->protocol = eth_type_trans(skb, dev);
+               dprintk(KERN_DEBUG "%s: nv_rx_process: %d bytes, proto %d accepted.\n",
+                                       dev->name, len, skb->protocol);
+#ifdef CONFIG_FORCEDETH_NAPI
+               netif_receive_skb(skb);
+#else
+               netif_rx(skb);
+#endif
+               dev->last_rx = jiffies;
+               np->stats.rx_packets++;
+               np->stats.rx_bytes += len;
+next_pkt:
+               if (unlikely(np->get_rx.orig++ == np->last_rx.orig))
+                       np->get_rx.orig = np->first_rx.orig;
+               if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx))
+                       np->get_rx_ctx = np->first_rx_ctx;
        }
+
+       return rx_processed_cnt;
 }
 
-static int nv_rx_process(struct net_device *dev, int limit)
+static int nv_rx_process_optimized(struct net_device *dev, int limit)
 {
        struct fe_priv *np = netdev_priv(dev);
        u32 flags;
        u32 vlanflags = 0;
-       int count;
-
-       for (count = 0; count < limit; ++count) {
-               struct sk_buff *skb;
-               int len;
-               int i;
-               if (np->cur_rx - np->refill_rx >= np->rx_ring_size)
-                       break;  /* we scanned the whole ring - do not continue */
-
-               i = np->cur_rx % np->rx_ring_size;
-               if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
-                       flags = le32_to_cpu(np->rx_ring.orig[i].flaglen);
-                       len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver);
-               } else {
-                       flags = le32_to_cpu(np->rx_ring.ex[i].flaglen);
-                       len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver);
-                       vlanflags = le32_to_cpu(np->rx_ring.ex[i].buflow);
-               }
+       u32 rx_processed_cnt = 0;
+       struct sk_buff *skb;
+       int len;
 
-               dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, flags 0x%x.\n",
-                                       dev->name, np->cur_rx, flags);
+       while((np->get_rx.ex != np->put_rx.ex) &&
+             !((flags = le32_to_cpu(np->get_rx.ex->flaglen)) & NV_RX2_AVAIL) &&
+             (rx_processed_cnt++ < limit)) {
 
-               if (flags & NV_RX_AVAIL)
-                       break;  /* still owned by hardware, */
+               dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: flags 0x%x.\n",
+                                       dev->name, flags);
 
                /*
                 * the packet is for us - immediately tear down the pci mapping.
                 * TODO: check if a prefetch of the first cacheline improves
                 * the performance.
                 */
-               pci_unmap_single(np->pci_dev, np->rx_dma[i],
-                               np->rx_skbuff[i]->end-np->rx_skbuff[i]->data,
+               pci_unmap_single(np->pci_dev, np->get_rx_ctx->dma,
+                               np->get_rx_ctx->dma_len,
                                PCI_DMA_FROMDEVICE);
+               skb = np->get_rx_ctx->skb;
+               np->get_rx_ctx->skb = NULL;
 
                {
                        int j;
@@ -1864,123 +2281,90 @@ static int nv_rx_process(struct net_device *dev, int limit)
                        for (j=0; j<64; j++) {
                                if ((j%16) == 0)
                                        dprintk("\n%03x:", j);
-                               dprintk(" %02x", ((unsigned char*)np->rx_skbuff[i]->data)[j]);
+                               dprintk(" %02x", ((unsigned char*)skb->data)[j]);
                        }
                        dprintk("\n");
                }
                /* look at what we actually got: */
-               if (np->desc_ver == DESC_VER_1) {
-                       if (!(flags & NV_RX_DESCRIPTORVALID))
-                               goto next_pkt;
-
-                       if (flags & NV_RX_ERROR) {
-                               if (flags & NV_RX_MISSEDFRAME) {
-                                       np->stats.rx_missed_errors++;
-                                       np->stats.rx_errors++;
-                                       goto next_pkt;
-                               }
-                               if (flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) {
-                                       np->stats.rx_errors++;
-                                       goto next_pkt;
-                               }
-                               if (flags & NV_RX_CRCERR) {
-                                       np->stats.rx_crc_errors++;
-                                       np->stats.rx_errors++;
-                                       goto next_pkt;
-                               }
-                               if (flags & NV_RX_OVERFLOW) {
-                                       np->stats.rx_over_errors++;
-                                       np->stats.rx_errors++;
-                                       goto next_pkt;
-                               }
-                               if (flags & NV_RX_ERROR4) {
-                                       len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
-                                       if (len < 0) {
-                                               np->stats.rx_errors++;
-                                               goto next_pkt;
-                                       }
-                               }
-                               /* framing errors are soft errors. */
-                               if (flags & NV_RX_FRAMINGERR) {
-                                       if (flags & NV_RX_SUBSTRACT1) {
-                                               len--;
-                                       }
-                               }
-                       }
-               } else {
-                       if (!(flags & NV_RX2_DESCRIPTORVALID))
-                               goto next_pkt;
-
-                       if (flags & NV_RX2_ERROR) {
-                               if (flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) {
-                                       np->stats.rx_errors++;
-                                       goto next_pkt;
-                               }
-                               if (flags & NV_RX2_CRCERR) {
-                                       np->stats.rx_crc_errors++;
-                                       np->stats.rx_errors++;
-                                       goto next_pkt;
-                               }
-                               if (flags & NV_RX2_OVERFLOW) {
-                                       np->stats.rx_over_errors++;
-                                       np->stats.rx_errors++;
-                                       goto next_pkt;
-                               }
+               if (likely(flags & NV_RX2_DESCRIPTORVALID)) {
+                       len = flags & LEN_MASK_V2;
+                       if (unlikely(flags & NV_RX2_ERROR)) {
                                if (flags & NV_RX2_ERROR4) {
-                                       len = nv_getlen(dev, np->rx_skbuff[i]->data, len);
+                                       len = nv_getlen(dev, skb->data, len);
                                        if (len < 0) {
-                                               np->stats.rx_errors++;
+                                               dev_kfree_skb(skb);
                                                goto next_pkt;
                                        }
                                }
                                /* framing errors are soft errors */
-                               if (flags & NV_RX2_FRAMINGERR) {
+                               else if (flags & NV_RX2_FRAMINGERR) {
                                        if (flags & NV_RX2_SUBSTRACT1) {
                                                len--;
                                        }
                                }
+                               /* the rest are hard errors */
+                               else {
+                                       dev_kfree_skb(skb);
+                                       goto next_pkt;
+                               }
                        }
-                       if (np->rx_csum) {
-                               flags &= NV_RX2_CHECKSUMMASK;
-                               if (flags == NV_RX2_CHECKSUMOK1 ||
-                                   flags == NV_RX2_CHECKSUMOK2 ||
-                                   flags == NV_RX2_CHECKSUMOK3) {
-                                       dprintk(KERN_DEBUG "%s: hw checksum hit!.\n", dev->name);
-                                       np->rx_skbuff[i]->ip_summed = CHECKSUM_UNNECESSARY;
-                               } else {
-                                       dprintk(KERN_DEBUG "%s: hwchecksum miss!.\n", dev->name);
+
+                       if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK2)/*ip and tcp */ {
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+                       } else {
+                               if ((flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK1 ||
+                                   (flags & NV_RX2_CHECKSUMMASK) == NV_RX2_CHECKSUMOK3) {
+                                       skb->ip_summed = CHECKSUM_UNNECESSARY;
                                }
                        }
-               }
-               /* got a valid packet - forward it to the network core */
-               skb = np->rx_skbuff[i];
-               np->rx_skbuff[i] = NULL;
 
-               skb_put(skb, len);
-               skb->protocol = eth_type_trans(skb, dev);
-               dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n",
-                                       dev->name, np->cur_rx, len, skb->protocol);
+                       /* got a valid packet - forward it to the network core */
+                       skb_put(skb, len);
+                       skb->protocol = eth_type_trans(skb, dev);
+                       prefetch(skb->data);
+
+                       dprintk(KERN_DEBUG "%s: nv_rx_process_optimized: %d bytes, proto %d accepted.\n",
+                               dev->name, len, skb->protocol);
+
+                       if (likely(!np->vlangrp)) {
 #ifdef CONFIG_FORCEDETH_NAPI
-               if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
-                       vlan_hwaccel_receive_skb(skb, np->vlangrp,
-                                                vlanflags & NV_RX3_VLAN_TAG_MASK);
-               else
-                       netif_receive_skb(skb);
+                               netif_receive_skb(skb);
 #else
-               if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT))
-                       vlan_hwaccel_rx(skb, np->vlangrp,
-                                       vlanflags & NV_RX3_VLAN_TAG_MASK);
-               else
-                       netif_rx(skb);
+                               netif_rx(skb);
 #endif
-               dev->last_rx = jiffies;
-               np->stats.rx_packets++;
-               np->stats.rx_bytes += len;
+                       } else {
+                               vlanflags = le32_to_cpu(np->get_rx.ex->buflow);
+                               if (vlanflags & NV_RX3_VLAN_TAG_PRESENT) {
+#ifdef CONFIG_FORCEDETH_NAPI
+                                       vlan_hwaccel_receive_skb(skb, np->vlangrp,
+                                                                vlanflags & NV_RX3_VLAN_TAG_MASK);
+#else
+                                       vlan_hwaccel_rx(skb, np->vlangrp,
+                                                       vlanflags & NV_RX3_VLAN_TAG_MASK);
+#endif
+                               } else {
+#ifdef CONFIG_FORCEDETH_NAPI
+                                       netif_receive_skb(skb);
+#else
+                                       netif_rx(skb);
+#endif
+                               }
+                       }
+
+                       dev->last_rx = jiffies;
+                       np->stats.rx_packets++;
+                       np->stats.rx_bytes += len;
+               } else {
+                       dev_kfree_skb(skb);
+               }
 next_pkt:
-               np->cur_rx++;
+               if (unlikely(np->get_rx.ex++ == np->last_rx.ex))
+                       np->get_rx.ex = np->first_rx.ex;
+               if (unlikely(np->get_rx_ctx++ == np->last_rx_ctx))
+                       np->get_rx_ctx = np->first_rx_ctx;
        }
 
-       return count;
+       return rx_processed_cnt;
 }
 
 static void set_bufsize(struct net_device *dev)
@@ -2456,7 +2840,6 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
                        events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
                        writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
                }
-               pci_push(base);
                dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
                if (!(events & np->irqmask))
                        break;
@@ -2465,22 +2848,46 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
                nv_tx_done(dev);
                spin_unlock(&np->lock);
 
-               if (events & NVREG_IRQ_LINK) {
+#ifdef CONFIG_FORCEDETH_NAPI
+               if (events & NVREG_IRQ_RX_ALL) {
+                       netif_rx_schedule(dev);
+
+                       /* Disable furthur receive irq's */
+                       spin_lock(&np->lock);
+                       np->irqmask &= ~NVREG_IRQ_RX_ALL;
+
+                       if (np->msi_flags & NV_MSI_X_ENABLED)
+                               writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
+                       else
+                               writel(np->irqmask, base + NvRegIrqMask);
+                       spin_unlock(&np->lock);
+               }
+#else
+               if (nv_rx_process(dev, dev->weight)) {
+                       if (unlikely(nv_alloc_rx(dev))) {
+                               spin_lock(&np->lock);
+                               if (!np->in_shutdown)
+                                       mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+                               spin_unlock(&np->lock);
+                       }
+               }
+#endif
+               if (unlikely(events & NVREG_IRQ_LINK)) {
                        spin_lock(&np->lock);
                        nv_link_irq(dev);
                        spin_unlock(&np->lock);
                }
-               if (np->need_linktimer && time_after(jiffies, np->link_timeout)) {
+               if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
                        spin_lock(&np->lock);
                        nv_linkchange(dev);
                        spin_unlock(&np->lock);
                        np->link_timeout = jiffies + LINK_TIMEOUT;
                }
-               if (events & (NVREG_IRQ_TX_ERR)) {
+               if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
                        dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
                                                dev->name, events);
                }
-               if (events & (NVREG_IRQ_UNKNOWN)) {
+               if (unlikely(events & (NVREG_IRQ_UNKNOWN))) {
                        printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
                                                dev->name, events);
                }
@@ -2501,6 +2908,63 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
                        spin_unlock(&np->lock);
                        break;
                }
+               if (unlikely(i > max_interrupt_work)) {
+                       spin_lock(&np->lock);
+                       /* disable interrupts on the nic */
+                       if (!(np->msi_flags & NV_MSI_X_ENABLED))
+                               writel(0, base + NvRegIrqMask);
+                       else
+                               writel(np->irqmask, base + NvRegIrqMask);
+                       pci_push(base);
+
+                       if (!np->in_shutdown) {
+                               np->nic_poll_irq = np->irqmask;
+                               mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+                       }
+                       printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
+                       spin_unlock(&np->lock);
+                       break;
+               }
+
+       }
+       dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
+
+       return IRQ_RETVAL(i);
+}
+
+#define TX_WORK_PER_LOOP  64
+#define RX_WORK_PER_LOOP  64
+/**
+ * All _optimized functions are used to help increase performance
+ * (reduce CPU and increase throughput). They use descripter version 3,
+ * compiler directives, and reduce memory accesses.
+ */
+static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
+{
+       struct net_device *dev = (struct net_device *) data;
+       struct fe_priv *np = netdev_priv(dev);
+       u8 __iomem *base = get_hwbase(dev);
+       u32 events;
+       int i;
+
+       dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name);
+
+       for (i=0; ; i++) {
+               if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
+                       events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
+                       writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
+               } else {
+                       events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
+                       writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
+               }
+               dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
+               if (!(events & np->irqmask))
+                       break;
+
+               spin_lock(&np->lock);
+               nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+               spin_unlock(&np->lock);
+
 #ifdef CONFIG_FORCEDETH_NAPI
                if (events & NVREG_IRQ_RX_ALL) {
                        netif_rx_schedule(dev);
@@ -2516,15 +2980,53 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
                        spin_unlock(&np->lock);
                }
 #else
-               nv_rx_process(dev, dev->weight);
-               if (nv_alloc_rx(dev)) {
+               if (nv_rx_process_optimized(dev, dev->weight)) {
+                       if (unlikely(nv_alloc_rx_optimized(dev))) {
+                               spin_lock(&np->lock);
+                               if (!np->in_shutdown)
+                                       mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+                               spin_unlock(&np->lock);
+                       }
+               }
+#endif
+               if (unlikely(events & NVREG_IRQ_LINK)) {
                        spin_lock(&np->lock);
-                       if (!np->in_shutdown)
-                               mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+                       nv_link_irq(dev);
                        spin_unlock(&np->lock);
                }
-#endif
-               if (i > max_interrupt_work) {
+               if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
+                       spin_lock(&np->lock);
+                       nv_linkchange(dev);
+                       spin_unlock(&np->lock);
+                       np->link_timeout = jiffies + LINK_TIMEOUT;
+               }
+               if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
+                       dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
+                                               dev->name, events);
+               }
+               if (unlikely(events & (NVREG_IRQ_UNKNOWN))) {
+                       printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
+                                               dev->name, events);
+               }
+               if (unlikely(events & NVREG_IRQ_RECOVER_ERROR)) {
+                       spin_lock(&np->lock);
+                       /* disable interrupts on the nic */
+                       if (!(np->msi_flags & NV_MSI_X_ENABLED))
+                               writel(0, base + NvRegIrqMask);
+                       else
+                               writel(np->irqmask, base + NvRegIrqMask);
+                       pci_push(base);
+
+                       if (!np->in_shutdown) {
+                               np->nic_poll_irq = np->irqmask;
+                               np->recover_error = 1;
+                               mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+                       }
+                       spin_unlock(&np->lock);
+                       break;
+               }
+
+               if (unlikely(i > max_interrupt_work)) {
                        spin_lock(&np->lock);
                        /* disable interrupts on the nic */
                        if (!(np->msi_flags & NV_MSI_X_ENABLED))
@@ -2543,7 +3045,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
                }
 
        }
-       dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
+       dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name);
 
        return IRQ_RETVAL(i);
 }
@@ -2562,20 +3064,19 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
        for (i=0; ; i++) {
                events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_TX_ALL;
                writel(NVREG_IRQ_TX_ALL, base + NvRegMSIXIrqStatus);
-               pci_push(base);
                dprintk(KERN_DEBUG "%s: tx irq: %08x\n", dev->name, events);
                if (!(events & np->irqmask))
                        break;
 
                spin_lock_irqsave(&np->lock, flags);
-               nv_tx_done(dev);
+               nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
                spin_unlock_irqrestore(&np->lock, flags);
 
-               if (events & (NVREG_IRQ_TX_ERR)) {
+               if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
                        dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
                                                dev->name, events);
                }
-               if (i > max_interrupt_work) {
+               if (unlikely(i > max_interrupt_work)) {
                        spin_lock_irqsave(&np->lock, flags);
                        /* disable interrupts on the nic */
                        writel(NVREG_IRQ_TX_ALL, base + NvRegIrqMask);
@@ -2604,7 +3105,10 @@ static int nv_napi_poll(struct net_device *dev, int *budget)
        u8 __iomem *base = get_hwbase(dev);
        unsigned long flags;
 
-       pkts = nv_rx_process(dev, limit);
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               pkts = nv_rx_process(dev, limit);
+       else
+               pkts = nv_rx_process_optimized(dev, limit);
 
        if (nv_alloc_rx(dev)) {
                spin_lock_irqsave(&np->lock, flags);
@@ -2670,20 +3174,20 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
        for (i=0; ; i++) {
                events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
                writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
-               pci_push(base);
                dprintk(KERN_DEBUG "%s: rx irq: %08x\n", dev->name, events);
                if (!(events & np->irqmask))
                        break;
 
-               nv_rx_process(dev, dev->weight);
-               if (nv_alloc_rx(dev)) {
-                       spin_lock_irqsave(&np->lock, flags);
-                       if (!np->in_shutdown)
-                               mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
-                       spin_unlock_irqrestore(&np->lock, flags);
+               if (nv_rx_process_optimized(dev, dev->weight)) {
+                       if (unlikely(nv_alloc_rx_optimized(dev))) {
+                               spin_lock_irqsave(&np->lock, flags);
+                               if (!np->in_shutdown)
+                                       mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
+                               spin_unlock_irqrestore(&np->lock, flags);
+                       }
                }
 
-               if (i > max_interrupt_work) {
+               if (unlikely(i > max_interrupt_work)) {
                        spin_lock_irqsave(&np->lock, flags);
                        /* disable interrupts on the nic */
                        writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
@@ -2718,11 +3222,15 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)
        for (i=0; ; i++) {
                events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_OTHER;
                writel(NVREG_IRQ_OTHER, base + NvRegMSIXIrqStatus);
-               pci_push(base);
                dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
                if (!(events & np->irqmask))
                        break;
 
+               /* check tx in case we reached max loop limit in tx isr */
+               spin_lock_irqsave(&np->lock, flags);
+               nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+               spin_unlock_irqrestore(&np->lock, flags);
+
                if (events & NVREG_IRQ_LINK) {
                        spin_lock_irqsave(&np->lock, flags);
                        nv_link_irq(dev);
@@ -2752,7 +3260,7 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)
                        printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
                                                dev->name, events);
                }
-               if (i > max_interrupt_work) {
+               if (unlikely(i > max_interrupt_work)) {
                        spin_lock_irqsave(&np->lock, flags);
                        /* disable interrupts on the nic */
                        writel(NVREG_IRQ_OTHER, base + NvRegIrqMask);
@@ -2835,6 +3343,16 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
        u8 __iomem *base = get_hwbase(dev);
        int ret = 1;
        int i;
+       irqreturn_t (*handler)(int foo, void *data);
+
+       if (intr_test) {
+               handler = nv_nic_irq_test;
+       } else {
+               if (np->desc_ver == DESC_VER_3)
+                       handler = nv_nic_irq_optimized;
+               else
+                       handler = nv_nic_irq;
+       }
 
        if (np->msi_flags & NV_MSI_X_CAPABLE) {
                for (i = 0; i < (np->msi_flags & NV_MSI_X_VECTORS_MASK); i++) {
@@ -2872,10 +3390,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                                set_msix_vector_map(dev, NV_MSI_X_VECTOR_OTHER, NVREG_IRQ_OTHER);
                        } else {
                                /* Request irq for all interrupts */
-                               if ((!intr_test &&
-                                    request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
-                                   (intr_test &&
-                                    request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
+                               if (request_irq(np->msi_x_entry[NV_MSI_X_VECTOR_ALL].vector, handler, IRQF_SHARED, dev->name, dev) != 0) {
                                        printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
                                        pci_disable_msix(np->pci_dev);
                                        np->msi_flags &= ~NV_MSI_X_ENABLED;
@@ -2891,8 +3406,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
        if (ret != 0 && np->msi_flags & NV_MSI_CAPABLE) {
                if ((ret = pci_enable_msi(np->pci_dev)) == 0) {
                        np->msi_flags |= NV_MSI_ENABLED;
-                       if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
-                           (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0)) {
+                       if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0) {
                                printk(KERN_INFO "forcedeth: request_irq failed %d\n", ret);
                                pci_disable_msi(np->pci_dev);
                                np->msi_flags &= ~NV_MSI_ENABLED;
@@ -2907,8 +3421,7 @@ static int nv_request_irq(struct net_device *dev, int intr_test)
                }
        }
        if (ret != 0) {
-               if ((!intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq, IRQF_SHARED, dev->name, dev) != 0) ||
-                   (intr_test && request_irq(np->pci_dev->irq, &nv_nic_irq_test, IRQF_SHARED, dev->name, dev) != 0))
+               if (request_irq(np->pci_dev->irq, handler, IRQF_SHARED, dev->name, dev) != 0)
                        goto out_err;
 
        }
@@ -3051,47 +3564,8 @@ static void nv_do_stats_poll(unsigned long data)
 {
        struct net_device *dev = (struct net_device *) data;
        struct fe_priv *np = netdev_priv(dev);
-       u8 __iomem *base = get_hwbase(dev);
 
-       np->estats.tx_bytes += readl(base + NvRegTxCnt);
-       np->estats.tx_zero_rexmt += readl(base + NvRegTxZeroReXmt);
-       np->estats.tx_one_rexmt += readl(base + NvRegTxOneReXmt);
-       np->estats.tx_many_rexmt += readl(base + NvRegTxManyReXmt);
-       np->estats.tx_late_collision += readl(base + NvRegTxLateCol);
-       np->estats.tx_fifo_errors += readl(base + NvRegTxUnderflow);
-       np->estats.tx_carrier_errors += readl(base + NvRegTxLossCarrier);
-       np->estats.tx_excess_deferral += readl(base + NvRegTxExcessDef);
-       np->estats.tx_retry_error += readl(base + NvRegTxRetryErr);
-       np->estats.tx_deferral += readl(base + NvRegTxDef);
-       np->estats.tx_packets += readl(base + NvRegTxFrame);
-       np->estats.tx_pause += readl(base + NvRegTxPause);
-       np->estats.rx_frame_error += readl(base + NvRegRxFrameErr);
-       np->estats.rx_extra_byte += readl(base + NvRegRxExtraByte);
-       np->estats.rx_late_collision += readl(base + NvRegRxLateCol);
-       np->estats.rx_runt += readl(base + NvRegRxRunt);
-       np->estats.rx_frame_too_long += readl(base + NvRegRxFrameTooLong);
-       np->estats.rx_over_errors += readl(base + NvRegRxOverflow);
-       np->estats.rx_crc_errors += readl(base + NvRegRxFCSErr);
-       np->estats.rx_frame_align_error += readl(base + NvRegRxFrameAlignErr);
-       np->estats.rx_length_error += readl(base + NvRegRxLenErr);
-       np->estats.rx_unicast += readl(base + NvRegRxUnicast);
-       np->estats.rx_multicast += readl(base + NvRegRxMulticast);
-       np->estats.rx_broadcast += readl(base + NvRegRxBroadcast);
-       np->estats.rx_bytes += readl(base + NvRegRxCnt);
-       np->estats.rx_pause += readl(base + NvRegRxPause);
-       np->estats.rx_drop_frame += readl(base + NvRegRxDropFrame);
-       np->estats.rx_packets =
-               np->estats.rx_unicast +
-               np->estats.rx_multicast +
-               np->estats.rx_broadcast;
-       np->estats.rx_errors_total =
-               np->estats.rx_crc_errors +
-               np->estats.rx_over_errors +
-               np->estats.rx_frame_error +
-               (np->estats.rx_frame_align_error - np->estats.rx_extra_byte) +
-               np->estats.rx_late_collision +
-               np->estats.rx_runt +
-               np->estats.rx_frame_too_long;
+       nv_get_hw_stats(dev);
 
        if (!np->in_shutdown)
                mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL);
@@ -3465,7 +3939,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
 {
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
-       u8 *rxtx_ring, *rx_skbuff, *tx_skbuff, *rx_dma, *tx_dma, *tx_dma_len;
+       u8 *rxtx_ring, *rx_skbuff, *tx_skbuff;
        dma_addr_t ring_addr;
 
        if (ring->rx_pending < RX_RING_MIN ||
@@ -3491,12 +3965,9 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
                                            sizeof(struct ring_desc_ex) * (ring->rx_pending + ring->tx_pending),
                                            &ring_addr);
        }
-       rx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->rx_pending, GFP_KERNEL);
-       rx_dma = kmalloc(sizeof(dma_addr_t) * ring->rx_pending, GFP_KERNEL);
-       tx_skbuff = kmalloc(sizeof(struct sk_buff*) * ring->tx_pending, GFP_KERNEL);
-       tx_dma = kmalloc(sizeof(dma_addr_t) * ring->tx_pending, GFP_KERNEL);
-       tx_dma_len = kmalloc(sizeof(unsigned int) * ring->tx_pending, GFP_KERNEL);
-       if (!rxtx_ring || !rx_skbuff || !rx_dma || !tx_skbuff || !tx_dma || !tx_dma_len) {
+       rx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->rx_pending, GFP_KERNEL);
+       tx_skbuff = kmalloc(sizeof(struct nv_skb_map) * ring->tx_pending, GFP_KERNEL);
+       if (!rxtx_ring || !rx_skbuff || !tx_skbuff) {
                /* fall back to old rings */
                if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
                        if (rxtx_ring)
@@ -3509,14 +3980,8 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
                }
                if (rx_skbuff)
                        kfree(rx_skbuff);
-               if (rx_dma)
-                       kfree(rx_dma);
                if (tx_skbuff)
                        kfree(tx_skbuff);
-               if (tx_dma)
-                       kfree(tx_dma);
-               if (tx_dma_len)
-                       kfree(tx_dma_len);
                goto exit;
        }
 
@@ -3538,8 +4003,6 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
        /* set new values */
        np->rx_ring_size = ring->rx_pending;
        np->tx_ring_size = ring->tx_pending;
-       np->tx_limit_stop = ring->tx_pending - TX_LIMIT_DIFFERENCE;
-       np->tx_limit_start = ring->tx_pending - TX_LIMIT_DIFFERENCE - 1;
        if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
                np->rx_ring.orig = (struct ring_desc*)rxtx_ring;
                np->tx_ring.orig = &np->rx_ring.orig[np->rx_ring_size];
@@ -3547,18 +4010,12 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
                np->rx_ring.ex = (struct ring_desc_ex*)rxtx_ring;
                np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
        }
-       np->rx_skbuff = (struct sk_buff**)rx_skbuff;
-       np->rx_dma = (dma_addr_t*)rx_dma;
-       np->tx_skbuff = (struct sk_buff**)tx_skbuff;
-       np->tx_dma = (dma_addr_t*)tx_dma;
-       np->tx_dma_len = (unsigned int*)tx_dma_len;
+       np->rx_skb = (struct nv_skb_map*)rx_skbuff;
+       np->tx_skb = (struct nv_skb_map*)tx_skbuff;
        np->ring_addr = ring_addr;
 
-       memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
-       memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
-       memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
-       memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
-       memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
+       memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
+       memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
 
        if (netif_running(dev)) {
                /* reinit driver view of the queues */
@@ -3727,8 +4184,10 @@ static int nv_get_stats_count(struct net_device *dev)
 {
        struct fe_priv *np = netdev_priv(dev);
 
-       if (np->driver_data & DEV_HAS_STATISTICS)
-               return sizeof(struct nv_ethtool_stats)/sizeof(u64);
+       if (np->driver_data & DEV_HAS_STATISTICS_V1)
+               return NV_DEV_STATISTICS_V1_COUNT;
+       else if (np->driver_data & DEV_HAS_STATISTICS_V2)
+               return NV_DEV_STATISTICS_V2_COUNT;
        else
                return 0;
 }
@@ -3955,7 +4414,7 @@ static int nv_loopback_test(struct net_device *dev)
                        dprintk(KERN_DEBUG "%s: loopback len mismatch %d vs %d\n",
                                dev->name, len, pkt_len);
                } else {
-                       rx_skb = np->rx_skbuff[0];
+                       rx_skb = np->rx_skb[0].skb;
                        for (i = 0; i < pkt_len; i++) {
                                if (rx_skb->data[i] != (u8)(i & 0xff)) {
                                        ret = 0;
@@ -4315,7 +4774,7 @@ static int nv_open(struct net_device *dev)
                mod_timer(&np->oom_kick, jiffies + OOM_REFILL);
 
        /* start statistics timer */
-       if (np->driver_data & DEV_HAS_STATISTICS)
+       if (np->driver_data & (DEV_HAS_STATISTICS_V1|DEV_HAS_STATISTICS_V2))
                mod_timer(&np->stats_poll, jiffies + STATS_INTERVAL);
 
        spin_unlock_irq(&np->lock);
@@ -4412,7 +4871,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        if (err < 0)
                goto out_disable;
 
-       if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS))
+       if (id->driver_data & (DEV_HAS_VLAN|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V2))
+               np->register_size = NV_PCI_REGSZ_VER3;
+       else if (id->driver_data & DEV_HAS_STATISTICS_V1)
                np->register_size = NV_PCI_REGSZ_VER2;
        else
                np->register_size = NV_PCI_REGSZ_VER1;
@@ -4475,10 +4936,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                np->rx_csum = 1;
                np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK;
                dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG;
-#ifdef NETIF_F_TSO
                dev->features |= NETIF_F_TSO;
-#endif
-       }
+       }
 
        np->vlanctl_bits = 0;
        if (id->driver_data & DEV_HAS_VLAN) {
@@ -4512,8 +4971,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 
        np->rx_ring_size = RX_RING_DEFAULT;
        np->tx_ring_size = TX_RING_DEFAULT;
-       np->tx_limit_stop = np->tx_ring_size - TX_LIMIT_DIFFERENCE;
-       np->tx_limit_start = np->tx_ring_size - TX_LIMIT_DIFFERENCE - 1;
 
        if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) {
                np->rx_ring.orig = pci_alloc_consistent(pci_dev,
@@ -4530,22 +4987,19 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                        goto out_unmap;
                np->tx_ring.ex = &np->rx_ring.ex[np->rx_ring_size];
        }
-       np->rx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->rx_ring_size, GFP_KERNEL);
-       np->rx_dma = kmalloc(sizeof(dma_addr_t) * np->rx_ring_size, GFP_KERNEL);
-       np->tx_skbuff = kmalloc(sizeof(struct sk_buff*) * np->tx_ring_size, GFP_KERNEL);
-       np->tx_dma = kmalloc(sizeof(dma_addr_t) * np->tx_ring_size, GFP_KERNEL);
-       np->tx_dma_len = kmalloc(sizeof(unsigned int) * np->tx_ring_size, GFP_KERNEL);
-       if (!np->rx_skbuff || !np->rx_dma || !np->tx_skbuff || !np->tx_dma || !np->tx_dma_len)
+       np->rx_skb = kmalloc(sizeof(struct nv_skb_map) * np->rx_ring_size, GFP_KERNEL);
+       np->tx_skb = kmalloc(sizeof(struct nv_skb_map) * np->tx_ring_size, GFP_KERNEL);
+       if (!np->rx_skb || !np->tx_skb)
                goto out_freering;
-       memset(np->rx_skbuff, 0, sizeof(struct sk_buff*) * np->rx_ring_size);
-       memset(np->rx_dma, 0, sizeof(dma_addr_t) * np->rx_ring_size);
-       memset(np->tx_skbuff, 0, sizeof(struct sk_buff*) * np->tx_ring_size);
-       memset(np->tx_dma, 0, sizeof(dma_addr_t) * np->tx_ring_size);
-       memset(np->tx_dma_len, 0, sizeof(unsigned int) * np->tx_ring_size);
+       memset(np->rx_skb, 0, sizeof(struct nv_skb_map) * np->rx_ring_size);
+       memset(np->tx_skb, 0, sizeof(struct nv_skb_map) * np->tx_ring_size);
 
        dev->open = nv_open;
        dev->stop = nv_close;
-       dev->hard_start_xmit = nv_start_xmit;
+       if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2)
+               dev->hard_start_xmit = nv_start_xmit;
+       else
+               dev->hard_start_xmit = nv_start_xmit_optimized;
        dev->get_stats = nv_get_stats;
        dev->change_mtu = nv_change_mtu;
        dev->set_mac_address = nv_set_mac_address;
@@ -4553,7 +5007,7 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
 #ifdef CONFIG_NET_POLL_CONTROLLER
        dev->poll_controller = nv_poll_controller;
 #endif
-       dev->weight = 64;
+       dev->weight = RX_WORK_PER_LOOP;
 #ifdef CONFIG_FORCEDETH_NAPI
        dev->poll = nv_napi_poll;
 #endif
@@ -4868,83 +5322,83 @@ static struct pci_device_id pci_tbl[] = {
        },
        {       /* CK804 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
        },
        {       /* CK804 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
        },
        {       /* MCP04 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
        },
        {       /* MCP04 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1,
        },
        {       /* MCP51 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
        },
        {       /* MCP51 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
        },
        {       /* MCP55 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {       /* MCP55 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN|DEV_HAS_MSI|DEV_HAS_MSI_X|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {       /* MCP61 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {       /* MCP61 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {       /* MCP61 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {       /* MCP61 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {       /* MCP65 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {       /* MCP65 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {       /* MCP65 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {       /* MCP65 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {       /* MCP67 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {       /* MCP67 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {       /* MCP67 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {       /* MCP67 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
+               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT,
        },
        {0,},
 };
index 844c136..7dc5185 100644 (file)
@@ -3034,7 +3034,7 @@ static int __init hp100_module_init(void)
                goto out2;
 #endif
 #ifdef CONFIG_PCI
-       err = pci_module_init(&hp100_pci_driver);
+       err = pci_register_driver(&hp100_pci_driver);
        if (err && err != -ENODEV)
                goto out3;
 #endif
index 2194b56..0e9ba3c 100644 (file)
@@ -1102,7 +1102,7 @@ static struct net_device * __init veth_probe_one(int vlan,
        }
 
        kobject_init(&port->kobject);
-       port->kobject.parent = &dev->class_dev.kobj;
+       port->kobject.parent = &dev->dev.kobj;
        port->kobject.ktype  = &veth_port_ktype;
        kobject_set_name(&port->kobject, "veth_port");
        if (0 != kobject_add(&port->kobject))
index f4aba43..cf30a10 100644 (file)
@@ -61,9 +61,7 @@
 #include <net/pkt_sched.h>
 #include <linux/list.h>
 #include <linux/reboot.h>
-#ifdef NETIF_F_TSO
 #include <net/checksum.h>
-#endif
 
 #include <linux/ethtool.h>
 #include <linux/if_vlan.h>
index 82c044d..d6628bd 100644 (file)
@@ -82,10 +82,8 @@ static struct ixgb_stats ixgb_gstrings_stats[] = {
        {"tx_restart_queue", IXGB_STAT(restart_queue) },
        {"rx_long_length_errors", IXGB_STAT(stats.roc)},
        {"rx_short_length_errors", IXGB_STAT(stats.ruc)},
-#ifdef NETIF_F_TSO
        {"tx_tcp_seg_good", IXGB_STAT(stats.tsctc)},
        {"tx_tcp_seg_failed", IXGB_STAT(stats.tsctfc)},
-#endif
        {"rx_flow_control_xon", IXGB_STAT(stats.xonrxc)},
        {"rx_flow_control_xoff", IXGB_STAT(stats.xoffrxc)},
        {"tx_flow_control_xon", IXGB_STAT(stats.xontxc)},
@@ -240,7 +238,6 @@ ixgb_set_tx_csum(struct net_device *netdev, uint32_t data)
        return 0;
 }
 
-#ifdef NETIF_F_TSO
 static int
 ixgb_set_tso(struct net_device *netdev, uint32_t data)
 {
@@ -250,7 +247,6 @@ ixgb_set_tso(struct net_device *netdev, uint32_t data)
                netdev->features &= ~NETIF_F_TSO;
        return 0;
 } 
-#endif /* NETIF_F_TSO */
 
 static uint32_t
 ixgb_get_msglevel(struct net_device *netdev)
@@ -722,10 +718,8 @@ static const struct ethtool_ops ixgb_ethtool_ops = {
        .set_sg = ethtool_op_set_sg,
        .get_msglevel = ixgb_get_msglevel,
        .set_msglevel = ixgb_set_msglevel,
-#ifdef NETIF_F_TSO
        .get_tso = ethtool_op_get_tso,
        .set_tso = ixgb_set_tso,
-#endif
        .get_strings = ixgb_get_strings,
        .phys_id = ixgb_phys_id,
        .get_stats_count = ixgb_get_stats_count,
index a083a91..0c36828 100644 (file)
@@ -456,9 +456,7 @@ ixgb_probe(struct pci_dev *pdev,
                           NETIF_F_HW_VLAN_TX |
                           NETIF_F_HW_VLAN_RX |
                           NETIF_F_HW_VLAN_FILTER;
-#ifdef NETIF_F_TSO
        netdev->features |= NETIF_F_TSO;
-#endif
 #ifdef NETIF_F_LLTX
        netdev->features |= NETIF_F_LLTX;
 #endif
@@ -1176,7 +1174,6 @@ ixgb_watchdog(unsigned long data)
 static int
 ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
 {
-#ifdef NETIF_F_TSO
        struct ixgb_context_desc *context_desc;
        unsigned int i;
        uint8_t ipcss, ipcso, tucss, tucso, hdr_len;
@@ -1233,7 +1230,6 @@ ixgb_tso(struct ixgb_adapter *adapter, struct sk_buff *skb)
 
                return 1;
        }
-#endif
 
        return 0;
 }
@@ -1609,7 +1605,7 @@ ixgb_update_stats(struct ixgb_adapter *adapter)
        struct pci_dev *pdev = adapter->pdev;
 
        /* Prevent stats update while adapter is being reset */
-       if (pdev->error_state && pdev->error_state != pci_channel_io_normal)
+       if (pci_channel_offline(pdev))
                return;
 
        if((netdev->flags & IFF_PROMISC) || (netdev->flags & IFF_ALLMULTI) ||
index 25b559b..e67361e 100644 (file)
@@ -27,8 +27,6 @@
 
 #include "macb.h"
 
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
-
 #define RX_BUFFER_SIZE         128
 #define RX_RING_SIZE           512
 #define RX_RING_BYTES          (sizeof(struct dma_desc) * RX_RING_SIZE)
@@ -945,10 +943,10 @@ static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
        return ret;
 }
 
-static ssize_t macb_mii_show(const struct class_device *cd, char *buf,
+static ssize_t macb_mii_show(const struct device *_dev, char *buf,
                        unsigned long addr)
 {
-       struct net_device *dev = to_net_dev(cd);
+       struct net_device *dev = to_net_dev(_dev);
        struct macb *bp = netdev_priv(dev);
        ssize_t ret = -EINVAL;
 
@@ -962,11 +960,13 @@ static ssize_t macb_mii_show(const struct class_device *cd, char *buf,
 }
 
 #define MII_ENTRY(name, addr)                                  \
-static ssize_t show_##name(struct class_device *cd, char *buf) \
+static ssize_t show_##name(struct device *_dev,                        \
+                          struct device_attribute *attr,       \
+                          char *buf)                           \
 {                                                              \
-       return macb_mii_show(cd, buf, addr);                    \
+       return macb_mii_show(_dev, buf, addr);                  \
 }                                                              \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
 
 MII_ENTRY(bmcr, MII_BMCR);
 MII_ENTRY(bmsr, MII_BMSR);
@@ -977,13 +977,13 @@ MII_ENTRY(lpa, MII_LPA);
 MII_ENTRY(expansion, MII_EXPANSION);
 
 static struct attribute *macb_mii_attrs[] = {
-       &class_device_attr_bmcr.attr,
-       &class_device_attr_bmsr.attr,
-       &class_device_attr_physid1.attr,
-       &class_device_attr_physid2.attr,
-       &class_device_attr_advertise.attr,
-       &class_device_attr_lpa.attr,
-       &class_device_attr_expansion.attr,
+       &dev_attr_bmcr.attr,
+       &dev_attr_bmsr.attr,
+       &dev_attr_physid1.attr,
+       &dev_attr_physid2.attr,
+       &dev_attr_advertise.attr,
+       &dev_attr_lpa.attr,
+       &dev_attr_expansion.attr,
        NULL,
 };
 
@@ -994,17 +994,17 @@ static struct attribute_group macb_mii_group = {
 
 static void macb_unregister_sysfs(struct net_device *net)
 {
-       struct class_device *class_dev = &net->class_dev;
+       struct device *_dev = &net->dev;
 
-       sysfs_remove_group(&class_dev->kobj, &macb_mii_group);
+       sysfs_remove_group(&_dev->kobj, &macb_mii_group);
 }
 
 static int macb_register_sysfs(struct net_device *net)
 {
-       struct class_device *class_dev = &net->class_dev;
+       struct device *_dev = &net->dev;
        int ret;
 
-       ret = sysfs_create_group(&class_dev->kobj, &macb_mii_group);
+       ret = sysfs_create_group(&_dev->kobj, &macb_mii_group);
        if (ret)
                printk(KERN_WARNING
                       "%s: sysfs mii attribute registration failed: %d\n",
@@ -1046,6 +1046,14 @@ static int __devinit macb_probe(struct platform_device *pdev)
 
        spin_lock_init(&bp->lock);
 
+#if defined(CONFIG_ARCH_AT91)
+       bp->pclk = clk_get(&pdev->dev, "macb_clk");
+       if (IS_ERR(bp->pclk)) {
+               dev_err(&pdev->dev, "failed to get macb_clk\n");
+               goto err_out_free_dev;
+       }
+       clk_enable(bp->pclk);
+#else
        bp->pclk = clk_get(&pdev->dev, "pclk");
        if (IS_ERR(bp->pclk)) {
                dev_err(&pdev->dev, "failed to get pclk\n");
@@ -1059,6 +1067,7 @@ static int __devinit macb_probe(struct platform_device *pdev)
 
        clk_enable(bp->pclk);
        clk_enable(bp->hclk);
+#endif
 
        bp->regs = ioremap(regs->start, regs->end - regs->start + 1);
        if (!bp->regs) {
@@ -1119,9 +1128,17 @@ static int __devinit macb_probe(struct platform_device *pdev)
 
        pdata = pdev->dev.platform_data;
        if (pdata && pdata->is_rmii)
+#if defined(CONFIG_ARCH_AT91)
+               macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) );
+#else
                macb_writel(bp, USRIO, 0);
+#endif
        else
+#if defined(CONFIG_ARCH_AT91)
+               macb_writel(bp, USRIO, MACB_BIT(CLKEN));
+#else
                macb_writel(bp, USRIO, MACB_BIT(MII));
+#endif
 
        bp->tx_pending = DEF_TX_RING_PENDING;
 
@@ -1148,9 +1165,11 @@ err_out_free_irq:
 err_out_iounmap:
        iounmap(bp->regs);
 err_out_disable_clocks:
+#ifndef CONFIG_ARCH_AT91
        clk_disable(bp->hclk);
-       clk_disable(bp->pclk);
        clk_put(bp->hclk);
+#endif
+       clk_disable(bp->pclk);
 err_out_put_pclk:
        clk_put(bp->pclk);
 err_out_free_dev:
@@ -1173,9 +1192,11 @@ static int __devexit macb_remove(struct platform_device *pdev)
                unregister_netdev(dev);
                free_irq(dev->irq, dev);
                iounmap(bp->regs);
+#ifndef CONFIG_ARCH_AT91
                clk_disable(bp->hclk);
-               clk_disable(bp->pclk);
                clk_put(bp->hclk);
+#endif
+               clk_disable(bp->pclk);
                clk_put(bp->pclk);
                free_netdev(dev);
                platform_set_drvdata(pdev, NULL);
index 27bf0ae..b3bb218 100644 (file)
 #define MACB_SOF_OFFSET                                30
 #define MACB_SOF_SIZE                          2
 
-/* Bitfields in USRIO */
+/* Bitfields in USRIO (AVR32) */
 #define MACB_MII_OFFSET                                0
 #define MACB_MII_SIZE                          1
 #define MACB_EAM_OFFSET                                1
 #define MACB_TX_PAUSE_ZERO_OFFSET              3
 #define MACB_TX_PAUSE_ZERO_SIZE                        1
 
+/* Bitfields in USRIO (AT91) */
+#define MACB_RMII_OFFSET                       0
+#define MACB_RMII_SIZE                         1
+#define MACB_CLKEN_OFFSET                      1
+#define MACB_CLKEN_SIZE                                1
+
 /* Bitfields in WOL */
 #define MACB_IP_OFFSET                         0
 #define MACB_IP_SIZE                           16
index 2907cfb..9ec24f0 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/init.h>
 #include <linux/crc32.h>
 #include <linux/spinlock.h>
+#include <linux/bitrev.h>
 #include <asm/prom.h>
 #include <asm/dbdma.h>
 #include <asm/io.h>
@@ -74,7 +75,6 @@ struct mace_data {
 #define PRIV_BYTES     (sizeof(struct mace_data) \
        + (N_RX_RING + NCMDS_TX * N_TX_RING + 3) * sizeof(struct dbdma_cmd))
 
-static int bitrev(int);
 static int mace_open(struct net_device *dev);
 static int mace_close(struct net_device *dev);
 static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev);
@@ -96,18 +96,6 @@ static void __mace_set_address(struct net_device *dev, void *addr);
  */
 static unsigned char *dummy_buf;
 
-/* Bit-reverse one byte of an ethernet hardware address. */
-static inline int
-bitrev(int b)
-{
-    int d = 0, i;
-
-    for (i = 0; i < 8; ++i, b >>= 1)
-       d = (d << 1) | (b & 1);
-    return d;
-}
-
-
 static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_id *match)
 {
        struct device_node *mace = macio_get_of_node(mdev);
@@ -173,7 +161,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i
 
        rev = addr[0] == 0 && addr[1] == 0xA0;
        for (j = 0; j < 6; ++j) {
-               dev->dev_addr[j] = rev? bitrev(addr[j]): addr[j];
+               dev->dev_addr[j] = rev ? bitrev8(addr[j]): addr[j];
        }
        mp->chipid = (in_8(&mp->mace->chipid_hi) << 8) |
                        in_8(&mp->mace->chipid_lo);
index 464e4a6..5d541e8 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/delay.h>
 #include <linux/string.h>
 #include <linux/crc32.h>
+#include <linux/bitrev.h>
 #include <asm/io.h>
 #include <asm/pgtable.h>
 #include <asm/irq.h>
@@ -81,19 +82,6 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id);
 static irqreturn_t mace_dma_intr(int irq, void *dev_id);
 static void mace_tx_timeout(struct net_device *dev);
 
-/* Bit-reverse one byte of an ethernet hardware address. */
-
-static int bitrev(int b)
-{
-       int d = 0, i;
-
-       for (i = 0; i < 8; ++i, b >>= 1) {
-               d = (d << 1) | (b & 1);
-       }
-
-       return d;
-}
-
 /*
  * Load a receive DMA channel with a base address and ring length
  */
@@ -219,12 +207,12 @@ struct net_device *mace_probe(int unit)
        addr = (void *)MACE_PROM;
 
        for (j = 0; j < 6; ++j) {
-               u8 v=bitrev(addr[j<<4]);
+               u8 v = bitrev8(addr[j<<4]);
                checksum ^= v;
                dev->dev_addr[j] = v;
        }
        for (; j < 8; ++j) {
-               checksum ^= bitrev(addr[j<<4]);
+               checksum ^= bitrev8(addr[j<<4]);
        }
 
        if (checksum != 0xFF) {
index 393d995..24f6050 100644 (file)
@@ -121,16 +121,12 @@ enum macsonic_type {
  * For reversing the PROM address
  */
 
-static unsigned char nibbletab[] = {0, 8, 4, 12, 2, 10, 6, 14,
-                                   1, 9, 5, 13, 3, 11, 7, 15};
-
 static inline void bit_reverse_addr(unsigned char addr[6])
 {
        int i;
 
        for(i = 0; i < 6; i++)
-               addr[i] = ((nibbletab[addr[i] & 0xf] << 4) |
-                          nibbletab[(addr[i] >> 4) &0xf]);
+               addr[i] = bitrev8(addr[i]);
 }
 
 int __init macsonic_init(struct net_device* dev)
index 61cbd4a..030924f 100644 (file)
@@ -1412,10 +1412,8 @@ static const struct ethtool_ops myri10ge_ethtool_ops = {
        .set_tx_csum = ethtool_op_set_tx_hw_csum,
        .get_sg = ethtool_op_get_sg,
        .set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
        .get_tso = ethtool_op_get_tso,
        .set_tso = ethtool_op_set_tso,
-#endif
        .get_strings = myri10ge_get_strings,
        .get_stats_count = myri10ge_get_stats_count,
        .get_ethtool_stats = myri10ge_get_ethtool_stats,
@@ -1975,13 +1973,11 @@ again:
        mss = 0;
        max_segments = MXGEFW_MAX_SEND_DESC;
 
-#ifdef NETIF_F_TSO
        if (skb->len > (dev->mtu + ETH_HLEN)) {
                mss = skb_shinfo(skb)->gso_size;
                if (mss != 0)
                        max_segments = MYRI10GE_MAX_SEND_DESC_TSO;
        }
-#endif                         /*NETIF_F_TSO */
 
        if ((unlikely(avail < max_segments))) {
                /* we are out of transmit resources */
@@ -2013,7 +2009,6 @@ again:
 
        cum_len = 0;
 
-#ifdef NETIF_F_TSO
        if (mss) {              /* TSO */
                /* this removes any CKSUM flag from before */
                flags = (MXGEFW_FLAGS_TSO_HDR | MXGEFW_FLAGS_FIRST);
@@ -2029,7 +2024,6 @@ again:
                 * the checksum by parsing the header. */
                pseudo_hdr_offset = mss;
        } else
-#endif                         /*NETIF_F_TSO */
                /* Mark small packets, and pad out tiny packets */
        if (skb->len <= MXGEFW_SEND_SMALL_SIZE) {
                flags |= MXGEFW_FLAGS_SMALL;
@@ -2097,7 +2091,6 @@ again:
                                seglen = len;
                        flags_next = flags & ~MXGEFW_FLAGS_FIRST;
                        cum_len_next = cum_len + seglen;
-#ifdef NETIF_F_TSO
                        if (mss) {      /* TSO */
                                (req - rdma_count)->rdma_count = rdma_count + 1;
 
@@ -2124,7 +2117,6 @@ again:
                                            (small * MXGEFW_FLAGS_SMALL);
                                }
                        }
-#endif                         /* NETIF_F_TSO */
                        req->addr_high = high_swapped;
                        req->addr_low = htonl(low);
                        req->pseudo_hdr_offset = htons(pseudo_hdr_offset);
@@ -2161,14 +2153,12 @@ again:
        }
 
        (req - rdma_count)->rdma_count = rdma_count;
-#ifdef NETIF_F_TSO
        if (mss)
                do {
                        req--;
                        req->flags |= MXGEFW_FLAGS_TSO_LAST;
                } while (!(req->flags & (MXGEFW_FLAGS_TSO_CHOP |
                                         MXGEFW_FLAGS_FIRST)));
-#endif
        idx = ((count - 1) + tx->req) & tx->mask;
        tx->info[idx].last = 1;
        if (tx->wc_fifo == NULL)
index e8598b8..3f3896e 100644 (file)
 
 #include "netxen_nic_hw.h"
 
-#define NETXEN_NIC_BUILD_NO     "2"
 #define _NETXEN_NIC_LINUX_MAJOR 3
 #define _NETXEN_NIC_LINUX_MINOR 3
 #define _NETXEN_NIC_LINUX_SUBVERSION 3
-#define NETXEN_NIC_LINUX_VERSIONID  "3.3.3" "-" NETXEN_NIC_BUILD_NO
+#define NETXEN_NIC_LINUX_VERSIONID  "3.3.3"
+
+#define NUM_FLASH_SECTORS (64)
+#define FLASH_SECTOR_SIZE (64 * 1024)
+#define FLASH_TOTAL_SIZE  (NUM_FLASH_SECTORS * FLASH_SECTOR_SIZE)
 
 #define RCV_DESC_RINGSIZE      \
        (sizeof(struct rcv_desc) * adapter->max_rx_desc_count)
@@ -85,6 +88,7 @@
 #define NETXEN_RCV_PRODUCER_OFFSET     0
 #define NETXEN_RCV_PEG_DB_ID           2
 #define NETXEN_HOST_DUMMY_DMA_SIZE 1024
+#define FLASH_SUCCESS 0
 
 #define ADDR_IN_WINDOW1(off)   \
        ((off > NETXEN_CRB_PCIX_HOST2) && (off < NETXEN_CRB_MAX)) ? 1 : 0
@@ -1028,6 +1032,15 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val);
 void netxen_load_firmware(struct netxen_adapter *adapter);
 int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose);
 int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp);
+int netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, 
+                               u8 *bytes, size_t size);
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, 
+                               u8 *bytes, size_t size);
+int netxen_flash_unlock(struct netxen_adapter *adapter);
+int netxen_backup_crbinit(struct netxen_adapter *adapter);
+int netxen_flash_erase_secondary(struct netxen_adapter *adapter);
+int netxen_flash_erase_primary(struct netxen_adapter *adapter);
+
 int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data);
 int netxen_rom_se(struct netxen_adapter *adapter, int addr);
 int netxen_do_rom_se(struct netxen_adapter *adapter, int addr);
index c381d77..cc0efe2 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/delay.h>
 #include <asm/uaccess.h>
 #include <linux/pci.h>
 #include <asm/io.h>
@@ -94,17 +95,7 @@ static const char netxen_nic_gstrings_test[][ETH_GSTRING_LEN] = {
 
 static int netxen_nic_get_eeprom_len(struct net_device *dev)
 {
-       struct netxen_port *port = netdev_priv(dev);
-       struct netxen_adapter *adapter = port->adapter;
-       int n;
-
-       if ((netxen_rom_fast_read(adapter, 0, &n) == 0)
-           && (n & NETXEN_ROM_ROUNDUP)) {
-               n &= ~NETXEN_ROM_ROUNDUP;
-               if (n < NETXEN_MAX_EEPROM_LEN)
-                       return n;
-       }
-       return 0;
+       return FLASH_TOTAL_SIZE;
 }
 
 static void
@@ -440,18 +431,92 @@ netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        struct netxen_port *port = netdev_priv(dev);
        struct netxen_adapter *adapter = port->adapter;
        int offset;
+       int ret;
 
        if (eeprom->len == 0)
                return -EINVAL;
 
        eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16);
-       for (offset = 0; offset < eeprom->len; offset++)
-               if (netxen_rom_fast_read
-                   (adapter, (8 * offset) + 8, (int *)eeprom->data) == -1)
-                       return -EIO;
+       offset = eeprom->offset;
+
+       ret = netxen_rom_fast_read_words(adapter, offset, bytes, 
+                                               eeprom->len);
+       if (ret < 0)
+               return ret;
+
        return 0;
 }
 
+static int
+netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+                       u8 * bytes)
+{
+       struct netxen_port *port = netdev_priv(dev);
+       struct netxen_adapter *adapter = port->adapter;
+       int offset = eeprom->offset;
+       static int flash_start;
+       static int ready_to_flash;
+       int ret;
+
+       if (flash_start == 0) {
+               ret = netxen_flash_unlock(adapter);
+               if (ret < 0) {
+                       printk(KERN_ERR "%s: Flash unlock failed.\n",
+                               netxen_nic_driver_name);
+                       return ret;
+               }
+               printk(KERN_INFO "%s: flash unlocked. \n", 
+                       netxen_nic_driver_name);
+               ret = netxen_flash_erase_secondary(adapter);
+               if (ret != FLASH_SUCCESS) {
+                       printk(KERN_ERR "%s: Flash erase failed.\n", 
+                               netxen_nic_driver_name);
+                       return ret;
+               }
+               printk(KERN_INFO "%s: secondary flash erased successfully.\n", 
+                       netxen_nic_driver_name);
+               flash_start = 1;
+               return 0;
+       }
+
+       if (offset == BOOTLD_START) {
+               ret = netxen_flash_erase_primary(adapter);
+               if (ret != FLASH_SUCCESS) {
+                       printk(KERN_ERR "%s: Flash erase failed.\n", 
+                               netxen_nic_driver_name);
+                       return ret;
+               }
+
+               ret = netxen_rom_se(adapter, USER_START);
+               if (ret != FLASH_SUCCESS)
+                       return ret;
+               ret = netxen_rom_se(adapter, FIXED_START);
+               if (ret != FLASH_SUCCESS)
+                       return ret;
+
+               printk(KERN_INFO "%s: primary flash erased successfully\n", 
+                       netxen_nic_driver_name);
+
+               ret = netxen_backup_crbinit(adapter);
+               if (ret != FLASH_SUCCESS) {
+                       printk(KERN_ERR "%s: CRBinit backup failed.\n", 
+                               netxen_nic_driver_name);
+                       return ret;
+               }
+               printk(KERN_INFO "%s: CRBinit backup done.\n", 
+                       netxen_nic_driver_name);
+               ready_to_flash = 1;
+       }
+
+       if (!ready_to_flash) {
+               printk(KERN_ERR "%s: Invalid write sequence, returning...\n",
+                       netxen_nic_driver_name);
+               return -EINVAL;
+       }
+
+       return netxen_rom_fast_write_words(adapter, offset, bytes, eeprom->len);
+}
+
 static void
 netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
 {
@@ -721,6 +786,7 @@ struct ethtool_ops netxen_nic_ethtool_ops = {
        .get_link = netxen_nic_get_link,
        .get_eeprom_len = netxen_nic_get_eeprom_len,
        .get_eeprom = netxen_nic_get_eeprom,
+       .set_eeprom = netxen_nic_set_eeprom,
        .get_ringparam = netxen_nic_get_ringparam,
        .get_pauseparam = netxen_nic_get_pauseparam,
        .set_pauseparam = netxen_nic_set_pauseparam,
index 973af96..f7bb8c9 100644 (file)
@@ -110,6 +110,7 @@ static void crb_addr_transform_setup(void)
        crb_addr_transform(CAM);
        crb_addr_transform(C2C1);
        crb_addr_transform(C2C0);
+       crb_addr_transform(SMB);
 }
 
 int netxen_init_firmware(struct netxen_adapter *adapter)
@@ -276,6 +277,7 @@ unsigned long netxen_decode_crb_addr(unsigned long addr)
 
 static long rom_max_timeout = 10000;
 static long rom_lock_timeout = 1000000;
+static long rom_write_timeout = 700;
 
 static inline int rom_lock(struct netxen_adapter *adapter)
 {
@@ -404,7 +406,7 @@ do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
 {
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr);
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3);
-       udelay(100);            /* prevent bursting on CRB */
+       udelay(70);             /* prevent bursting on CRB */
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb);
        if (netxen_wait_rom_done(adapter)) {
@@ -413,13 +415,46 @@ do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
        }
        /* reset abyte_cnt and dummy_byte_cnt */
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
-       udelay(100);            /* prevent bursting on CRB */
+       udelay(70);             /* prevent bursting on CRB */
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
 
        *valp = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_ROM_RDATA);
        return 0;
 }
 
+static inline int 
+do_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
+                       u8 *bytes, size_t size)
+{
+       int addridx;
+       int ret = 0;
+
+       for (addridx = addr; addridx < (addr + size); addridx += 4) {
+               ret = do_rom_fast_read(adapter, addridx, (int *)bytes);
+               if (ret != 0)
+                       break;
+               bytes += 4;
+       }
+
+       return ret;
+}
+
+int
+netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, 
+                               u8 *bytes, size_t size)
+{
+       int ret;
+
+       ret = rom_lock(adapter);
+       if (ret < 0)
+               return ret;
+
+       ret = do_rom_fast_read_words(adapter, addr, bytes, size);
+
+       netxen_rom_unlock(adapter);
+       return ret;
+}
+
 int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
 {
        int ret;
@@ -443,6 +478,152 @@ int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data)
        netxen_rom_unlock(adapter);
        return ret;
 }
+
+static inline int do_rom_fast_write_words(struct netxen_adapter *adapter, 
+                                               int addr, u8 *bytes, size_t size)
+{
+       int addridx = addr;
+       int ret = 0;
+
+       while (addridx < (addr + size)) {
+               int last_attempt = 0;
+               int timeout = 0;
+               int data;
+
+               data = *(u32*)bytes;
+
+               ret = do_rom_fast_write(adapter, addridx, data);
+               if (ret < 0)
+                       return ret;
+                       
+               while(1) {
+                       int data1;
+
+                       do_rom_fast_read(adapter, addridx, &data1);
+                       if (data1 == data)
+                               break;
+
+                       if (timeout++ >= rom_write_timeout) {
+                               if (last_attempt++ < 4) {
+                                       ret = do_rom_fast_write(adapter, 
+                                                               addridx, data);
+                                       if (ret < 0)
+                                               return ret;
+                               }
+                               else {
+                                       printk(KERN_INFO "Data write did not "
+                                          "succeed at address 0x%x\n", addridx);
+                                       break;
+                               }
+                       }
+               }
+
+               bytes += 4;
+               addridx += 4;
+       }
+
+       return ret;
+}
+
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, 
+                                       u8 *bytes, size_t size)
+{
+       int ret = 0;
+
+       ret = rom_lock(adapter);
+       if (ret < 0)
+               return ret;
+
+       ret = do_rom_fast_write_words(adapter, addr, bytes, size);
+       netxen_rom_unlock(adapter);
+
+       return ret;
+}
+
+int netxen_rom_wrsr(struct netxen_adapter *adapter, int data)
+{
+       int ret;
+
+       ret = netxen_rom_wren(adapter);
+       if (ret < 0)
+               return ret;
+
+       netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_ROM_WDATA, data);
+       netxen_crb_writelit_adapter(adapter, 
+                                       NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0x1);
+
+       ret = netxen_wait_rom_done(adapter);
+       if (ret < 0)
+               return ret;
+
+       return netxen_rom_wip_poll(adapter);
+}
+
+int netxen_rom_rdsr(struct netxen_adapter *adapter)
+{
+       int ret;
+
+       ret = rom_lock(adapter);
+       if (ret < 0)
+               return ret;
+
+       ret = netxen_do_rom_rdsr(adapter);
+       netxen_rom_unlock(adapter);
+       return ret;
+}
+
+int netxen_backup_crbinit(struct netxen_adapter *adapter)
+{
+       int ret = FLASH_SUCCESS;
+       int val;
+       char *buffer = kmalloc(FLASH_SECTOR_SIZE, GFP_KERNEL);
+
+       if (!buffer)
+               return -ENOMEM; 
+       /* unlock sector 63 */
+       val = netxen_rom_rdsr(adapter);
+       val = val & 0xe3;
+       ret = netxen_rom_wrsr(adapter, val);
+       if (ret != FLASH_SUCCESS)
+               goto out_kfree;
+
+       ret = netxen_rom_wip_poll(adapter);
+       if (ret != FLASH_SUCCESS)
+               goto out_kfree;
+
+       /* copy  sector 0 to sector 63 */
+       ret = netxen_rom_fast_read_words(adapter, CRBINIT_START, 
+                                               buffer, FLASH_SECTOR_SIZE);
+       if (ret != FLASH_SUCCESS)
+               goto out_kfree;
+
+       ret = netxen_rom_fast_write_words(adapter, FIXED_START, 
+                                               buffer, FLASH_SECTOR_SIZE);
+       if (ret != FLASH_SUCCESS)
+               goto out_kfree;
+
+       /* lock sector 63 */
+       val = netxen_rom_rdsr(adapter);
+       if (!(val & 0x8)) {
+               val |= (0x1 << 2);
+               /* lock sector 63 */
+               if (netxen_rom_wrsr(adapter, val) == 0) {
+                       ret = netxen_rom_wip_poll(adapter);
+                       if (ret != FLASH_SUCCESS)
+                               goto out_kfree;
+
+                       /* lock SR writes */
+                       ret = netxen_rom_wip_poll(adapter);
+                       if (ret != FLASH_SUCCESS)
+                               goto out_kfree;
+               }
+       }
+
+out_kfree:
+       kfree(buffer);
+       return ret;
+}
+
 int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
 {
        netxen_rom_wren(adapter);
@@ -457,6 +638,27 @@ int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
        return netxen_rom_wip_poll(adapter);
 }
 
+void check_erased_flash(struct netxen_adapter *adapter, int addr)
+{
+       int i;
+       int val;
+       int count = 0, erased_errors = 0;
+       int range;
+
+       range = (addr == USER_START) ? FIXED_START : addr + FLASH_SECTOR_SIZE;
+       
+       for (i = addr; i < range; i += 4) {
+               netxen_rom_fast_read(adapter, i, &val);
+               if (val != 0xffffffff)
+                       erased_errors++;
+               count++;
+       }
+
+       if (erased_errors)
+               printk(KERN_INFO "0x%x out of 0x%x words fail to be erased "
+                       "for sector address: %x\n", erased_errors, count, addr);
+}
+
 int netxen_rom_se(struct netxen_adapter *adapter, int addr)
 {
        int ret = 0;
@@ -465,6 +667,68 @@ int netxen_rom_se(struct netxen_adapter *adapter, int addr)
        }
        ret = netxen_do_rom_se(adapter, addr);
        netxen_rom_unlock(adapter);
+       msleep(30);
+       check_erased_flash(adapter, addr);
+
+       return ret;
+}
+
+int
+netxen_flash_erase_sections(struct netxen_adapter *adapter, int start, int end)
+{
+       int ret = FLASH_SUCCESS;
+       int i;
+
+       for (i = start; i < end; i++) {
+               ret = netxen_rom_se(adapter, i * FLASH_SECTOR_SIZE);
+               if (ret)
+                       break;
+               ret = netxen_rom_wip_poll(adapter);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return ret;
+}
+
+int
+netxen_flash_erase_secondary(struct netxen_adapter *adapter)
+{
+       int ret = FLASH_SUCCESS;
+       int start, end;
+
+       start = SECONDARY_START / FLASH_SECTOR_SIZE;
+       end   = USER_START / FLASH_SECTOR_SIZE;
+       ret = netxen_flash_erase_sections(adapter, start, end);
+
+       return ret;
+}
+
+int
+netxen_flash_erase_primary(struct netxen_adapter *adapter)
+{
+       int ret = FLASH_SUCCESS;
+       int start, end;
+
+       start = PRIMARY_START / FLASH_SECTOR_SIZE;
+       end   = SECONDARY_START / FLASH_SECTOR_SIZE;
+       ret = netxen_flash_erase_sections(adapter, start, end);
+
+       return ret;
+}
+
+int netxen_flash_unlock(struct netxen_adapter *adapter)
+{
+       int ret = 0;
+
+       ret = netxen_rom_wrsr(adapter, 0);
+       if (ret < 0)
+               return ret;
+
+       ret = netxen_rom_wren(adapter);
+       if (ret < 0)
+               return ret;
+
        return ret;
 }
 
@@ -543,9 +807,13 @@ int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose)
                }
                for (i = 0; i < n; i++) {
 
-                       off =
-                           netxen_decode_crb_addr((unsigned long)buf[i].addr) +
-                           NETXEN_PCI_CRBSPACE;
+                       off = netxen_decode_crb_addr((unsigned long)buf[i].addr);
+                       if (off == NETXEN_ADDR_ERROR) {
+                               printk(KERN_ERR"CRB init value out of range %lx\n",
+                                       buf[i].addr);
+                               continue;
+                       }
+                       off += NETXEN_PCI_CRBSPACE;
                        /* skipping cold reboot MAGIC */
                        if (off == NETXEN_CAM_RAM(0x1fc))
                                continue;
@@ -662,6 +930,7 @@ void netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
        int loops = 0;
 
        if (!pegtune_val) {
+               val = readl(NETXEN_CRB_NORMALIZE(adapter, CRB_CMDPEG_STATE));
                while (val != PHAN_INITIALIZE_COMPLETE && loops < 200000) {
                        udelay(100);
                        schedule();
diff --git a/drivers/net/oaknet.c b/drivers/net/oaknet.c
deleted file mode 100644 (file)
index 702e3e9..0000000
+++ /dev/null
@@ -1,666 +0,0 @@
-/*
- *
- *    Copyright (c) 1999-2000 Grant Erickson <grant@lcse.umn.edu>
- *
- *    Module name: oaknet.c
- *
- *    Description:
- *      Driver for the National Semiconductor DP83902AV Ethernet controller
- *      on-board the IBM PowerPC "Oak" evaluation board. Adapted from the
- *      various other 8390 drivers written by Donald Becker and Paul Gortmaker.
- *
- *      Additional inspiration from the "tcd8390.c" driver from TiVo, Inc.
- *      and "enetLib.c" from IBM.
- *
- */
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/init.h>
-#include <linux/jiffies.h>
-
-#include <asm/board.h>
-#include <asm/io.h>
-
-#include "8390.h"
-
-
-/* Preprocessor Defines */
-
-#if !defined(TRUE) || TRUE != 1
-#define        TRUE    1
-#endif
-
-#if !defined(FALSE) || FALSE != 0
-#define        FALSE   0
-#endif
-
-#define        OAKNET_START_PG         0x20    /* First page of TX buffer */
-#define        OAKNET_STOP_PG          0x40    /* Last pagge +1 of RX ring */
-
-#define        OAKNET_WAIT             (2 * HZ / 100)  /* 20 ms */
-
-/* Experimenting with some fixes for a broken driver... */
-
-#define        OAKNET_DISINT
-#define        OAKNET_HEADCHECK
-#define        OAKNET_RWFIX
-
-
-/* Global Variables */
-
-static const char *name = "National DP83902AV";
-
-static struct net_device *oaknet_devs;
-
-
-/* Function Prototypes */
-
-static int      oaknet_open(struct net_device *dev);
-static int      oaknet_close(struct net_device *dev);
-
-static void     oaknet_reset_8390(struct net_device *dev);
-static void     oaknet_get_8390_hdr(struct net_device *dev,
-                                    struct e8390_pkt_hdr *hdr, int ring_page);
-static void     oaknet_block_input(struct net_device *dev, int count,
-                                   struct sk_buff *skb, int ring_offset);
-static void     oaknet_block_output(struct net_device *dev, int count,
-                                    const unsigned char *buf, int start_page);
-
-static void     oaknet_dma_error(struct net_device *dev, const char *name);
-
-
-/*
- * int oaknet_init()
- *
- * Description:
- *   This routine performs all the necessary platform-specific initiali-
- *   zation and set-up for the IBM "Oak" evaluation board's National
- *   Semiconductor DP83902AV "ST-NIC" Ethernet controller.
- *
- * Input(s):
- *   N/A
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   0 if OK, otherwise system error number on error.
- *
- */
-static int __init oaknet_init(void)
-{
-       register int i;
-       int reg0, regd;
-       int ret = -ENOMEM;
-       struct net_device *dev;
-#if 0
-       unsigned long ioaddr = OAKNET_IO_BASE;
-#else
-       unsigned long ioaddr = ioremap(OAKNET_IO_BASE, OAKNET_IO_SIZE);
-#endif
-       bd_t *bip = (bd_t *)__res;
-
-       if (!ioaddr)
-               return -ENOMEM;
-
-       dev = alloc_ei_netdev();
-       if (!dev)
-               goto out_unmap;
-
-       ret = -EBUSY;
-       if (!request_region(OAKNET_IO_BASE, OAKNET_IO_SIZE, name))
-               goto out_dev;
-
-       /* Quick register check to see if the device is really there. */
-
-       ret = -ENODEV;
-       if ((reg0 = ei_ibp(ioaddr)) == 0xFF)
-               goto out_region;
-
-       /*
-        * That worked. Now a more thorough check, using the multicast
-        * address registers, that the device is definitely out there
-        * and semi-functional.
-        */
-
-       ei_obp(E8390_NODMA + E8390_PAGE1 + E8390_STOP, ioaddr + E8390_CMD);
-       regd = ei_ibp(ioaddr + 0x0D);
-       ei_obp(0xFF, ioaddr + 0x0D);
-       ei_obp(E8390_NODMA + E8390_PAGE0, ioaddr + E8390_CMD);
-       ei_ibp(ioaddr + EN0_COUNTER0);
-
-       /* It's no good. Fix things back up and leave. */
-
-       ret = -ENODEV;
-       if (ei_ibp(ioaddr + EN0_COUNTER0) != 0) {
-               ei_obp(reg0, ioaddr);
-               ei_obp(regd, ioaddr + 0x0D);
-               goto out_region;
-       }
-
-       SET_MODULE_OWNER(dev);
-
-       /*
-        * This controller is on an embedded board, so the base address
-        * and interrupt assignments are pre-assigned and unchageable.
-        */
-
-       dev->base_addr = ioaddr;
-       dev->irq = OAKNET_INT;
-
-       /*
-        * Disable all chip interrupts for now and ACK all pending
-        * interrupts.
-        */
-
-       ei_obp(0x0, ioaddr + EN0_IMR);
-       ei_obp(0xFF, ioaddr + EN0_ISR);
-
-       /* Attempt to get the interrupt line */
-
-       ret = -EAGAIN;
-       if (request_irq(dev->irq, ei_interrupt, 0, name, dev)) {
-               printk("%s: unable to request interrupt %d.\n",
-                      name, dev->irq);
-               goto out_region;
-       }
-
-       /* Tell the world about what and where we've found. */
-
-       printk("%s: %s at", dev->name, name);
-       for (i = 0; i < ETHER_ADDR_LEN; ++i) {
-               dev->dev_addr[i] = bip->bi_enetaddr[i];
-               printk("%c%.2x", (i ? ':' : ' '), dev->dev_addr[i]);
-       }
-       printk(", found at %#lx, using IRQ %d.\n", dev->base_addr, dev->irq);
-
-       /* Set up some required driver fields and then we're done. */
-
-       ei_status.name          = name;
-       ei_status.word16        = FALSE;
-       ei_status.tx_start_page = OAKNET_START_PG;
-       ei_status.rx_start_page = OAKNET_START_PG + TX_PAGES;
-       ei_status.stop_page     = OAKNET_STOP_PG;
-
-       ei_status.reset_8390    = &oaknet_reset_8390;
-       ei_status.block_input   = &oaknet_block_input;
-       ei_status.block_output  = &oaknet_block_output;
-       ei_status.get_8390_hdr  = &oaknet_get_8390_hdr;
-
-       dev->open = oaknet_open;
-       dev->stop = oaknet_close;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       dev->poll_controller = ei_poll;
-#endif
-
-       NS8390_init(dev, FALSE);
-       ret = register_netdev(dev);
-       if (ret)
-               goto out_irq;
-
-       oaknet_devs = dev;
-       return 0;
-
-out_irq;
-       free_irq(dev->irq, dev);
-out_region:
-       release_region(OAKNET_IO_BASE, OAKNET_IO_SIZE);
-out_dev:
-       free_netdev(dev);
-out_unmap:
-       iounmap(ioaddr);
-       return ret;
-}
-
-/*
- * static int oaknet_open()
- *
- * Description:
- *   This routine is a modest wrapper around ei_open, the 8390-generic,
- *   driver open routine. This just increments the module usage count
- *   and passes along the status from ei_open.
- *
- * Input(s):
- *  *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- *  *dev - Pointer to the device structure for this driver, potentially
- *         modified by ei_open.
- *
- * Returns:
- *   0 if OK, otherwise < 0 on error.
- *
- */
-static int
-oaknet_open(struct net_device *dev)
-{
-       int status = ei_open(dev);
-       return (status);
-}
-
-/*
- * static int oaknet_close()
- *
- * Description:
- *   This routine is a modest wrapper around ei_close, the 8390-generic,
- *   driver close routine. This just decrements the module usage count
- *   and passes along the status from ei_close.
- *
- * Input(s):
- *  *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- *  *dev - Pointer to the device structure for this driver, potentially
- *         modified by ei_close.
- *
- * Returns:
- *   0 if OK, otherwise < 0 on error.
- *
- */
-static int
-oaknet_close(struct net_device *dev)
-{
-       int status = ei_close(dev);
-       return (status);
-}
-
-/*
- * static void oaknet_reset_8390()
- *
- * Description:
- *   This routine resets the DP83902 chip.
- *
- * Input(s):
- *  *dev - Pointer to the device structure for this driver.
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-static void
-oaknet_reset_8390(struct net_device *dev)
-{
-       int base = E8390_BASE;
-
-       /*
-        * We have no provision of reseting the controller as is done
-        * in other drivers, such as "ne.c". However, the following
-        * seems to work well enough in the TiVo driver.
-        */
-
-       printk("Resetting %s...\n", dev->name);
-       ei_obp(E8390_STOP | E8390_NODMA | E8390_PAGE0, base + E8390_CMD);
-       ei_status.txing = 0;
-       ei_status.dmaing = 0;
-}
-
-/*
- * static void oaknet_get_8390_hdr()
- *
- * Description:
- *   This routine grabs the 8390-specific header. It's similar to the
- *   block input routine, but we don't need to be concerned with ring wrap
- *   as the header will be at the start of a page, so we optimize accordingly.
- *
- * Input(s):
- *  *dev       - Pointer to the device structure for this driver.
- *  *hdr       - Pointer to storage for the 8390-specific packet header.
- *   ring_page - ?
- *
- * Output(s):
- *  *hdr       - Pointer to the 8390-specific packet header for the just-
- *               received frame.
- *
- * Returns:
- *   N/A
- *
- */
-static void
-oaknet_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr,
-                   int ring_page)
-{
-       int base = dev->base_addr;
-
-       /*
-        * This should NOT happen. If it does, it is the LAST thing you'll
-        * see.
-        */
-
-       if (ei_status.dmaing) {
-               oaknet_dma_error(dev, "oaknet_get_8390_hdr");
-               return;
-       }
-
-       ei_status.dmaing |= 0x01;
-       outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, base + OAKNET_CMD);
-       outb_p(sizeof(struct e8390_pkt_hdr), base + EN0_RCNTLO);
-       outb_p(0, base + EN0_RCNTHI);
-       outb_p(0, base + EN0_RSARLO);           /* On page boundary */
-       outb_p(ring_page, base + EN0_RSARHI);
-       outb_p(E8390_RREAD + E8390_START, base + OAKNET_CMD);
-
-       if (ei_status.word16)
-               insw(base + OAKNET_DATA, hdr,
-                    sizeof(struct e8390_pkt_hdr) >> 1);
-       else
-               insb(base + OAKNET_DATA, hdr,
-                    sizeof(struct e8390_pkt_hdr));
-
-       /* Byte-swap the packet byte count */
-
-       hdr->count = le16_to_cpu(hdr->count);
-
-       outb_p(ENISR_RDC, base + EN0_ISR);      /* ACK Remote DMA interrupt */
-       ei_status.dmaing &= ~0x01;
-}
-
-/*
- * XXX - Document me.
- */
-static void
-oaknet_block_input(struct net_device *dev, int count, struct sk_buff *skb,
-                  int ring_offset)
-{
-       int base = OAKNET_BASE;
-       char *buf = skb->data;
-
-       /*
-        * This should NOT happen. If it does, it is the LAST thing you'll
-        * see.
-        */
-
-       if (ei_status.dmaing) {
-               oaknet_dma_error(dev, "oaknet_block_input");
-               return;
-       }
-
-#ifdef OAKNET_DISINT
-       save_flags(flags);
-       cli();
-#endif
-
-       ei_status.dmaing |= 0x01;
-       ei_obp(E8390_NODMA + E8390_PAGE0 + E8390_START, base + E8390_CMD);
-       ei_obp(count & 0xff, base + EN0_RCNTLO);
-       ei_obp(count >> 8, base + EN0_RCNTHI);
-       ei_obp(ring_offset & 0xff, base + EN0_RSARLO);
-       ei_obp(ring_offset >> 8, base + EN0_RSARHI);
-       ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
-       if (ei_status.word16) {
-               ei_isw(base + E8390_DATA, buf, count >> 1);
-               if (count & 0x01) {
-                       buf[count - 1] = ei_ib(base + E8390_DATA);
-#ifdef OAKNET_HEADCHECK
-                       bytes++;
-#endif
-               }
-       } else {
-               ei_isb(base + E8390_DATA, buf, count);
-       }
-#ifdef OAKNET_HEADCHECK
-       /*
-        * This was for the ALPHA version only, but enough people have
-        * been encountering problems so it is still here.  If you see
-        * this message you either 1) have a slightly incompatible clone
-        * or 2) have noise/speed problems with your bus.
-        */
-
-       /* DMA termination address check... */
-       {
-               int addr, tries = 20;
-               do {
-                       /* DON'T check for 'ei_ibp(EN0_ISR) & ENISR_RDC' here
-                          -- it's broken for Rx on some cards! */
-                       int high = ei_ibp(base + EN0_RSARHI);
-                       int low = ei_ibp(base + EN0_RSARLO);
-                       addr = (high << 8) + low;
-                       if (((ring_offset + bytes) & 0xff) == low)
-                               break;
-               } while (--tries > 0);
-               if (tries <= 0)
-                       printk("%s: RX transfer address mismatch,"
-                              "%#4.4x (expected) vs. %#4.4x (actual).\n",
-                              dev->name, ring_offset + bytes, addr);
-       }
-#endif
-       ei_obp(ENISR_RDC, base + EN0_ISR);      /* ACK Remote DMA interrupt */
-       ei_status.dmaing &= ~0x01;
-
-#ifdef OAKNET_DISINT
-       restore_flags(flags);
-#endif
-}
-
-/*
- * static void oaknet_block_output()
- *
- * Description:
- *   This routine...
- *
- * Input(s):
- *  *dev        - Pointer to the device structure for this driver.
- *   count      - Number of bytes to be transferred.
- *  *buf        -
- *   start_page -
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-static void
-oaknet_block_output(struct net_device *dev, int count,
-                   const unsigned char *buf, int start_page)
-{
-       int base = E8390_BASE;
-#if 0
-       int bug;
-#endif
-       unsigned long start;
-#ifdef OAKNET_DISINT
-       unsigned long flags;
-#endif
-#ifdef OAKNET_HEADCHECK
-       int retries = 0;
-#endif
-
-       /* Round the count up for word writes. */
-
-       if (ei_status.word16 && (count & 0x1))
-               count++;
-
-       /*
-        * This should NOT happen. If it does, it is the LAST thing you'll
-        * see.
-        */
-
-       if (ei_status.dmaing) {
-               oaknet_dma_error(dev, "oaknet_block_output");
-               return;
-       }
-
-#ifdef OAKNET_DISINT
-       save_flags(flags);
-       cli();
-#endif
-
-       ei_status.dmaing |= 0x01;
-
-       /* Make sure we are in page 0. */
-
-       ei_obp(E8390_PAGE0 + E8390_START + E8390_NODMA, base + E8390_CMD);
-
-#ifdef OAKNET_HEADCHECK
-retry:
-#endif
-
-#if 0
-       /*
-        * The 83902 documentation states that the processor needs to
-        * do a "dummy read" before doing the remote write to work
-        * around a chip bug they don't feel like fixing.
-        */
-
-       bug = 0;
-       while (1) {
-               unsigned int rdhi;
-               unsigned int rdlo;
-
-               /* Now the normal output. */
-               ei_obp(ENISR_RDC, base + EN0_ISR);
-               ei_obp(count & 0xff, base + EN0_RCNTLO);
-               ei_obp(count >> 8,   base + EN0_RCNTHI);
-               ei_obp(0x00, base + EN0_RSARLO);
-               ei_obp(start_page, base + EN0_RSARHI);
-
-               if (bug++)
-                       break;
-
-               /* Perform the dummy read */
-               rdhi = ei_ibp(base + EN0_CRDAHI);
-               rdlo = ei_ibp(base + EN0_CRDALO);
-               ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
-
-               while (1) {
-                       unsigned int nrdhi;
-                       unsigned int nrdlo;
-                       nrdhi = ei_ibp(base + EN0_CRDAHI);
-                       nrdlo = ei_ibp(base + EN0_CRDALO);
-                       if ((rdhi != nrdhi) || (rdlo != nrdlo))
-                               break;
-               }
-       }
-#else
-#ifdef OAKNET_RWFIX
-       /*
-        * Handle the read-before-write bug the same way as the
-        * Crynwr packet driver -- the Nat'l Semi. method doesn't work.
-        * Actually this doesn't always work either, but if you have
-        * problems with your 83902 this is better than nothing!
-        */
-
-       ei_obp(0x42, base + EN0_RCNTLO);
-       ei_obp(0x00, base + EN0_RCNTHI);
-       ei_obp(0x42, base + EN0_RSARLO);
-       ei_obp(0x00, base + EN0_RSARHI);
-       ei_obp(E8390_RREAD + E8390_START, base + E8390_CMD);
-       /* Make certain that the dummy read has occurred. */
-       udelay(6);
-#endif
-
-       ei_obp(ENISR_RDC, base + EN0_ISR);
-
-       /* Now the normal output. */
-       ei_obp(count & 0xff, base + EN0_RCNTLO);
-       ei_obp(count >> 8,   base + EN0_RCNTHI);
-       ei_obp(0x00, base + EN0_RSARLO);
-       ei_obp(start_page, base + EN0_RSARHI);
-#endif /* 0/1 */
-
-       ei_obp(E8390_RWRITE + E8390_START, base + E8390_CMD);
-       if (ei_status.word16) {
-               ei_osw(E8390_BASE + E8390_DATA, buf, count >> 1);
-       } else {
-               ei_osb(E8390_BASE + E8390_DATA, buf, count);
-       }
-
-#ifdef OAKNET_DISINT
-       restore_flags(flags);
-#endif
-
-       start = jiffies;
-
-#ifdef OAKNET_HEADCHECK
-       /*
-        * This was for the ALPHA version only, but enough people have
-        * been encountering problems so it is still here.
-        */
-
-       {
-               /* DMA termination address check... */
-               int addr, tries = 20;
-               do {
-                       int high = ei_ibp(base + EN0_RSARHI);
-                       int low = ei_ibp(base + EN0_RSARLO);
-                       addr = (high << 8) + low;
-                       if ((start_page << 8) + count == addr)
-                               break;
-               } while (--tries > 0);
-
-               if (tries <= 0) {
-                       printk("%s: Tx packet transfer address mismatch,"
-                              "%#4.4x (expected) vs. %#4.4x (actual).\n",
-                              dev->name, (start_page << 8) + count, addr);
-                       if (retries++ == 0)
-                               goto retry;
-               }
-       }
-#endif
-
-       while ((ei_ibp(base + EN0_ISR) & ENISR_RDC) == 0) {
-               if (time_after(jiffies, start + OAKNET_WAIT)) {
-                       printk("%s: timeout waiting for Tx RDC.\n", dev->name);
-                       oaknet_reset_8390(dev);
-                       NS8390_init(dev, TRUE);
-                       break;
-               }
-       }
-
-       ei_obp(ENISR_RDC, base + EN0_ISR);      /* Ack intr. */
-       ei_status.dmaing &= ~0x01;
-}
-
-/*
- * static void oaknet_dma_error()
- *
- * Description:
- *   This routine prints out a last-ditch informative message to the console
- *   indicating that a DMA error occurred. If you see this, it's the last
- *   thing you'll see.
- *
- * Input(s):
- *  *dev  - Pointer to the device structure for this driver.
- *  *name - Informative text (e.g. function name) indicating where the
- *          DMA error occurred.
- *
- * Output(s):
- *   N/A
- *
- * Returns:
- *   N/A
- *
- */
-static void
-oaknet_dma_error(struct net_device *dev, const char *name)
-{
-       printk(KERN_EMERG "%s: DMAing conflict in %s."
-              "[DMAstat:%d][irqlock:%d][intr:%ld]\n",
-              dev->name, name, ei_status.dmaing, ei_status.irqlock,
-              dev->interrupt);
-}
-
-/*
- * Oak Ethernet module unload interface.
- */
-static void __exit oaknet_cleanup_module (void)
-{
-       /* Convert to loop once driver supports multiple devices. */
-       unregister_netdev(oaknet_dev);
-       free_irq(oaknet_devs->irq, oaknet_devs);
-       release_region(oaknet_devs->base_addr, OAKNET_IO_SIZE);
-       iounmap(ioaddr);
-       free_netdev(oaknet_devs);
-}
-
-module_init(oaknet_init);
-module_exit(oaknet_cleanup_module);
-MODULE_LICENSE("GPL");
diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c
new file mode 100644 (file)
index 0000000..d670ac7
--- /dev/null
@@ -0,0 +1,1019 @@
+/*
+ * Copyright (C) 2006-2007 PA Semi, Inc
+ *
+ * Driver for the PA Semi PWRficient onchip 1G/10G Ethernet MACs
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <asm/dma-mapping.h>
+#include <linux/in.h>
+#include <linux/skbuff.h>
+
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <net/checksum.h>
+
+#include "pasemi_mac.h"
+
+
+/* TODO list
+ *
+ * - Get rid of pci_{read,write}_config(), map registers with ioremap
+ *   for performance
+ * - PHY support
+ * - Multicast support
+ * - Large MTU support
+ * - Other performance improvements
+ */
+
+
+/* Must be a power of two */
+#define RX_RING_SIZE 512
+#define TX_RING_SIZE 512
+
+#define TX_DESC(mac, num)      ((mac)->tx->desc[(num) & (TX_RING_SIZE-1)])
+#define TX_DESC_INFO(mac, num) ((mac)->tx->desc_info[(num) & (TX_RING_SIZE-1)])
+#define RX_DESC(mac, num)      ((mac)->rx->desc[(num) & (RX_RING_SIZE-1)])
+#define RX_DESC_INFO(mac, num) ((mac)->rx->desc_info[(num) & (RX_RING_SIZE-1)])
+#define RX_BUFF(mac, num)      ((mac)->rx->buffers[(num) & (RX_RING_SIZE-1)])
+
+#define BUF_SIZE 1646 /* 1500 MTU + ETH_HLEN + VLAN_HLEN + 2 64B cachelines */
+
+/* XXXOJN these should come out of the device tree some day */
+#define PAS_DMA_CAP_BASE   0xe00d0040
+#define PAS_DMA_CAP_SIZE   0x100
+#define PAS_DMA_COM_BASE   0xe00d0100
+#define PAS_DMA_COM_SIZE   0x100
+
+static struct pasdma_status *dma_status;
+
+static int pasemi_get_mac_addr(struct pasemi_mac *mac)
+{
+       struct pci_dev *pdev = mac->pdev;
+       struct device_node *dn = pci_device_to_OF_node(pdev);
+       const u8 *maddr;
+       u8 addr[6];
+
+       if (!dn) {
+               dev_dbg(&pdev->dev,
+                         "No device node for mac, not configuring\n");
+               return -ENOENT;
+       }
+
+       maddr = get_property(dn, "mac-address", NULL);
+       if (maddr == NULL) {
+               dev_warn(&pdev->dev,
+                        "no mac address in device tree, not configuring\n");
+               return -ENOENT;
+       }
+
+       if (sscanf(maddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &addr[0],
+                  &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]) != 6) {
+               dev_warn(&pdev->dev,
+                        "can't parse mac address, not configuring\n");
+               return -EINVAL;
+       }
+
+       memcpy(mac->mac_addr, addr, sizeof(addr));
+       return 0;
+}
+
+static int pasemi_mac_setup_rx_resources(struct net_device *dev)
+{
+       struct pasemi_mac_rxring *ring;
+       struct pasemi_mac *mac = netdev_priv(dev);
+       int chan_id = mac->dma_rxch;
+
+       ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+
+       if (!ring)
+               goto out_ring;
+
+       spin_lock_init(&ring->lock);
+
+       ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+                                 RX_RING_SIZE, GFP_KERNEL);
+
+       if (!ring->desc_info)
+               goto out_desc_info;
+
+       /* Allocate descriptors */
+       ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
+                                       RX_RING_SIZE *
+                                       sizeof(struct pas_dma_xct_descr),
+                                       &ring->dma, GFP_KERNEL);
+
+       if (!ring->desc)
+               goto out_desc;
+
+       memset(ring->desc, 0, RX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+
+       ring->buffers = dma_alloc_coherent(&mac->dma_pdev->dev,
+                                          RX_RING_SIZE * sizeof(u64),
+                                          &ring->buf_dma, GFP_KERNEL);
+       if (!ring->buffers)
+               goto out_buffers;
+
+       memset(ring->buffers, 0, RX_RING_SIZE * sizeof(u64));
+
+       pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEL(chan_id),
+                              PAS_DMA_RXCHAN_BASEL_BRBL(ring->dma));
+
+       pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_BASEU(chan_id),
+                              PAS_DMA_RXCHAN_BASEU_BRBH(ring->dma >> 32) |
+                              PAS_DMA_RXCHAN_BASEU_SIZ(RX_RING_SIZE >> 2));
+
+       pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXCHAN_CFG(chan_id),
+                              PAS_DMA_RXCHAN_CFG_HBU(1));
+
+       pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEL(mac->dma_if),
+                              PAS_DMA_RXINT_BASEL_BRBL(__pa(ring->buffers)));
+
+       pci_write_config_dword(mac->dma_pdev, PAS_DMA_RXINT_BASEU(mac->dma_if),
+                              PAS_DMA_RXINT_BASEU_BRBH(__pa(ring->buffers) >> 32) |
+                              PAS_DMA_RXINT_BASEU_SIZ(RX_RING_SIZE >> 3));
+
+       ring->next_to_fill = 0;
+       ring->next_to_clean = 0;
+
+       snprintf(ring->irq_name, sizeof(ring->irq_name),
+                "%s rx", dev->name);
+       mac->rx = ring;
+
+       return 0;
+
+out_buffers:
+       dma_free_coherent(&mac->dma_pdev->dev,
+                         RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+                         mac->rx->desc, mac->rx->dma);
+out_desc:
+       kfree(ring->desc_info);
+out_desc_info:
+       kfree(ring);
+out_ring:
+       return -ENOMEM;
+}
+
+
+static int pasemi_mac_setup_tx_resources(struct net_device *dev)
+{
+       struct pasemi_mac *mac = netdev_priv(dev);
+       u32 val;
+       int chan_id = mac->dma_txch;
+       struct pasemi_mac_txring *ring;
+
+       ring = kzalloc(sizeof(*ring), GFP_KERNEL);
+       if (!ring)
+               goto out_ring;
+
+       spin_lock_init(&ring->lock);
+
+       ring->desc_info = kzalloc(sizeof(struct pasemi_mac_buffer) *
+                                 TX_RING_SIZE, GFP_KERNEL);
+       if (!ring->desc_info)
+               goto out_desc_info;
+
+       /* Allocate descriptors */
+       ring->desc = dma_alloc_coherent(&mac->dma_pdev->dev,
+                                       TX_RING_SIZE *
+                                       sizeof(struct pas_dma_xct_descr),
+                                       &ring->dma, GFP_KERNEL);
+       if (!ring->desc)
+               goto out_desc;
+
+       memset(ring->desc, 0, TX_RING_SIZE * sizeof(struct pas_dma_xct_descr));
+
+       pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEL(chan_id),
+                              PAS_DMA_TXCHAN_BASEL_BRBL(ring->dma));
+       val = PAS_DMA_TXCHAN_BASEU_BRBH(ring->dma >> 32);
+       val |= PAS_DMA_TXCHAN_BASEU_SIZ(TX_RING_SIZE >> 2);
+
+       pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_BASEU(chan_id), val);
+
+       pci_write_config_dword(mac->dma_pdev, PAS_DMA_TXCHAN_CFG(chan_id),
+                              PAS_DMA_TXCHAN_CFG_TY_IFACE |
+                              PAS_DMA_TXCHAN_CFG_TATTR(mac->dma_if) |
+                              PAS_DMA_TXCHAN_CFG_UP |
+                              PAS_DMA_TXCHAN_CFG_WT(2));
+
+       ring->next_to_use = 0;
+       ring->next_to_clean = 0;
+
+       snprintf(ring->irq_name, sizeof(ring->irq_name),
+                "%s tx", dev->name);
+       mac->tx = ring;
+
+       return 0;
+
+out_desc:
+       kfree(ring->desc_info);
+out_desc_info:
+       kfree(ring);
+out_ring:
+       return -ENOMEM;
+}
+
+static void pasemi_mac_free_tx_resources(struct net_device *dev)
+{
+       struct pasemi_mac *mac = netdev_priv(dev);
+       unsigned int i;
+       struct pasemi_mac_buffer *info;
+       struct pas_dma_xct_descr *dp;
+
+       for (i = 0; i < TX_RING_SIZE; i++) {
+               info = &TX_DESC_INFO(mac, i);
+               dp = &TX_DESC(mac, i);
+               if (info->dma) {
+                       if (info->skb) {
+                               pci_unmap_single(mac->dma_pdev,
+                                                info->dma,
+                                                info->skb->len,
+                                                PCI_DMA_TODEVICE);
+                               dev_kfree_skb_any(info->skb);
+                       }
+                       info->dma = 0;
+                       info->skb = NULL;
+                       dp->mactx = 0;
+                       dp->ptr = 0;
+               }
+       }
+
+       dma_free_coherent(&mac->dma_pdev->dev,
+                         TX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+                         mac->tx->desc, mac->tx->dma);
+
+       kfree(mac->tx->desc_info);
+       kfree(mac->tx);
+       mac->tx = NULL;
+}
+
+static void pasemi_mac_free_rx_resources(struct net_device *dev)
+{
+       struct pasemi_mac *mac = netdev_priv(dev);
+       unsigned int i;
+       struct pasemi_mac_buffer *info;
+       struct pas_dma_xct_descr *dp;
+
+       for (i = 0; i < RX_RING_SIZE; i++) {
+               info = &RX_DESC_INFO(mac, i);
+               dp = &RX_DESC(mac, i);
+               if (info->dma) {
+                       if (info->skb) {
+                               pci_unmap_single(mac->dma_pdev,
+                                                info->dma,
+                                                info->skb->len,
+                                                PCI_DMA_FROMDEVICE);
+                               dev_kfree_skb_any(info->skb);
+                       }
+                       info->dma = 0;
+                       info->skb = NULL;
+                       dp->macrx = 0;
+                       dp->ptr = 0;
+               }
+       }
+
+       dma_free_coherent(&mac->dma_pdev->dev,
+                         RX_RING_SIZE * sizeof(struct pas_dma_xct_descr),
+                         mac->rx->desc, mac->rx->dma);
+
+       dma_free_coherent(&mac->dma_pdev->dev, RX_RING_SIZE * sizeof(u64),
+                         mac->rx->buffers, mac->rx->buf_dma);
+
+       kfree(mac->rx->desc_info);
+       kfree(mac->rx);
+       mac->rx = NULL;
+}
+
+static void pasemi_mac_replenish_rx_ring(struct net_device *dev)
+{
+       struct pasemi_mac *mac = netdev_priv(dev);
+       unsigned int i;
+       int start = mac->rx->next_to_fill;
+       unsigned int count;
+
+       count = (mac->rx->next_to_clean + RX_RING_SIZE -
+                mac->rx->next_to_fill) & (RX_RING_SIZE - 1);
+
+       /* Check to see if we're doing first-time setup */
+       if (unlikely(mac->rx->next_to_clean == 0 && mac->rx->next_to_fill == 0))
+               count = RX_RING_SIZE;
+
+       if (count <= 0)
+               return;
+
+       for (i = start; i < start + count; i++) {
+               struct pasemi_mac_buffer *info = &RX_DESC_INFO(mac, i);
+               u64 *buff = &RX_BUFF(mac, i);
+               struct sk_buff *skb;
+               dma_addr_t dma;
+
+               skb = dev_alloc_skb(BUF_SIZE);
+
+               if (!skb) {
+                       count = i - start;
+                       break;
+               }
+
+               skb->dev = dev;
+
+               dma = pci_map_single(mac->dma_pdev, skb->data, skb->len,
+                                    PCI_DMA_FROMDEVICE);
+
+               if (dma_mapping_error(dma)) {
+                       dev_kfree_skb_irq(info->skb);
+                       count = i - start;
+                       break;
+               }
+
+               info->skb = skb;
+               info->dma = dma;
+               *buff = XCT_RXB_LEN(BUF_SIZE) | XCT_RXB_ADDR(dma);
+       }
+
+       wmb();
+
+       pci_write_config_dword(mac->dma_pdev,
+                              PAS_DMA_RXCHAN_INCR(mac->dma_rxch),
+                              count);
+       pci_write_config_dword(mac->dma_pdev,
+                              PAS_DMA_RXINT_INCR(mac->dma_if),
+                              count);
+
+       mac->rx->next_to_fill += count;
+}
+
+static int pasemi_mac_clean_rx(struct pasemi_mac *mac, int limit)
+{
+       unsigned int i;
+       int start, count;
+
+       spin_lock(&mac->rx->lock);
+
+       start = mac->rx->next_to_clean;
+       count = 0;
+
+       for (i = start; i < (start + RX_RING_SIZE) && count < limit; i++) {
+               struct pas_dma_xct_descr *dp;
+               struct pasemi_mac_buffer *info;
+               struct sk_buff *skb;
+               unsigned int j, len;
+               dma_addr_t dma;
+
+               rmb();
+
+               dp = &RX_DESC(mac, i);
+
+               if (!(dp->macrx & XCT_MACRX_O))
+                       break;
+
+               count++;
+
+               info = NULL;
+
+               /* We have to scan for our skb since there's no way
+                * to back-map them from the descriptor, and if we
+                * have several receive channels then they might not
+                * show up in the same order as they were put on the
+                * interface ring.
+                */
+
+               dma = (dp->ptr & XCT_PTR_ADDR_M);
+               for (j = start; j < (start + RX_RING_SIZE); j++) {
+                       info = &RX_DESC_INFO(mac, j);
+                       if (info->dma == dma)
+                               break;
+               }
+
+               BUG_ON(!info);
+               BUG_ON(info->dma != dma);
+
+               pci_unmap_single(mac->dma_pdev, info->dma, info->skb->len,
+                                PCI_DMA_FROMDEVICE);
+
+               skb = info->skb;
+
+               len = (dp->macrx & XCT_MACRX_LLEN_M) >> XCT_MACRX_LLEN_S;
+
+               skb_put(skb, len);
+
+               skb->protocol = eth_type_trans(skb, mac->netdev);
+
+               if ((dp->macrx & XCT_MACRX_HTY_M) == XCT_MACRX_HTY_IPV4_OK) {
+                       skb->ip_summed = CHECKSUM_COMPLETE;
+                       skb->csum = (dp->macrx & XCT_MACRX_CSUM_M) >>
+                                          XCT_MACRX_CSUM_S;
+               } else
+                       skb->ip_summed = CHECKSUM_NONE;
+
+               mac->stats.rx_bytes += len;
+               mac->stats.rx_packets++;
+
+               netif_receive_skb(skb);
+
+               info->dma = 0;
+               info->skb = NULL;
+               dp->ptr = 0;
+               dp->macrx = 0;
+       }
+
+       mac->rx->next_to_clean += count;
+       pasemi_mac_replenish_rx_ring(mac->netdev);
+
+       spin_unlock(&mac->rx->lock);
+
+       return count;
+}
+
+static int pasemi_mac_clean_tx(struct pasemi_mac *mac)
+{
+       int i;
+       struct pasemi_mac_buffer *info;
+       struct pas_dma_xct_descr *dp;
+       int start, count;
+       int flags;
+
+       spin_lock_irqsave(&mac->tx->lock, flags);
+
+       start = mac->tx->next_to_clean;
+       count = 0;
+
+       for (i = start; i < mac->tx->next_to_use; i++) {
+               dp = &TX_DESC(mac, i);
+               if (!dp || (dp->mactx & XCT_MACTX_O))
+                       break;
+
+               count++;
+
+               info = &TX_DESC_INFO(mac, i);
+
+               pci_unmap_single(mac->dma_pdev, info->dma,
+                                info->skb->len, PCI_DMA_TODEVICE);
+               dev_kfree_skb_irq(info->skb);
+
+               info->skb = NULL;
+               info->dma = 0;
+               dp->mactx = 0;
+               dp->ptr = 0;
+       }
+       mac->tx->next_to_clean += count;
+       spin_unlock_irqrestore(&mac->tx->lock, flags);
+
+       return count;
+}
+
+
+static irqreturn_t pasemi_mac_rx_intr(int irq, void *data)
+{
+       struct net_device *dev = data;
+       struct pasemi_mac *mac = netdev_priv(dev);
+       unsigned int reg;
+
+       if (!(*mac->rx_status & PAS_STATUS_INT))
+               return IRQ_NONE;
+
+       netif_rx_schedule(dev);
+       pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+                              PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(0));
+
+       reg = PAS_IOB_DMA_RXCH_RESET_PINTC | PAS_IOB_DMA_RXCH_RESET_SINTC |
+             PAS_IOB_DMA_RXCH_RESET_DINTC;
+       if (*mac->rx_status & PAS_STATUS_TIMER)
+               reg |= PAS_IOB_DMA_RXCH_RESET_TINTC;
+
+       pci_write_config_dword(mac->iob_pdev,
+                              PAS_IOB_DMA_RXCH_RESET(mac->dma_rxch), reg);
+
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t pasemi_mac_tx_intr(int irq, void *data)
+{
+       struct net_device *dev = data;
+       struct pasemi_mac *mac = netdev_priv(dev);
+       unsigned int reg;
+       int was_full;
+
+       was_full = mac->tx->next_to_clean - mac->tx->next_to_use == TX_RING_SIZE;
+
+       if (!(*mac->tx_status & PAS_STATUS_INT))
+               return IRQ_NONE;
+
+       pasemi_mac_clean_tx(mac);
+
+       reg = PAS_IOB_DMA_TXCH_RESET_PINTC | PAS_IOB_DMA_TXCH_RESET_SINTC;
+       if (*mac->tx_status & PAS_STATUS_TIMER)
+               reg |= PAS_IOB_DMA_TXCH_RESET_TINTC;
+
+       pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_TXCH_RESET(mac->dma_txch),
+                              reg);
+
+       if (was_full)
+               netif_wake_queue(dev);
+
+       return IRQ_HANDLED;
+}
+
+static int pasemi_mac_open(struct net_device *dev)
+{
+       struct pasemi_mac *mac = netdev_priv(dev);
+       unsigned int flags;
+       int ret;
+
+       /* enable rx section */
+       pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_RXCMD,
+                              PAS_DMA_COM_RXCMD_EN);
+
+       /* enable tx section */
+       pci_write_config_dword(mac->dma_pdev, PAS_DMA_COM_TXCMD,
+                              PAS_DMA_COM_TXCMD_EN);
+
+       flags = PAS_MAC_CFG_TXP_FCE | PAS_MAC_CFG_TXP_FPC(3) |
+               PAS_MAC_CFG_TXP_SL(3) | PAS_MAC_CFG_TXP_COB(0xf) |
+               PAS_MAC_CFG_TXP_TIFT(8) | PAS_MAC_CFG_TXP_TIFG(12);
+
+       pci_write_config_dword(mac->pdev, PAS_MAC_CFG_TXP, flags);
+
+       flags = PAS_MAC_CFG_PCFG_S1 | PAS_MAC_CFG_PCFG_PE |
+               PAS_MAC_CFG_PCFG_PR | PAS_MAC_CFG_PCFG_CE;
+
+       flags |= PAS_MAC_CFG_PCFG_TSR_1G | PAS_MAC_CFG_PCFG_SPD_1G;
+
+       pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_RXCH_CFG(mac->dma_rxch),
+                              PAS_IOB_DMA_RXCH_CFG_CNTTH(30));
+
+       pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+                              PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+
+       pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+
+       ret = pasemi_mac_setup_rx_resources(dev);
+       if (ret)
+               goto out_rx_resources;
+
+       ret = pasemi_mac_setup_tx_resources(dev);
+       if (ret)
+               goto out_tx_resources;
+
+       pci_write_config_dword(mac->pdev, PAS_MAC_IPC_CHNL,
+                              PAS_MAC_IPC_CHNL_DCHNO(mac->dma_rxch) |
+                              PAS_MAC_IPC_CHNL_BCH(mac->dma_rxch));
+
+       /* enable rx if */
+       pci_write_config_dword(mac->dma_pdev,
+                              PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+                              PAS_DMA_RXINT_RCMDSTA_EN);
+
+       /* enable rx channel */
+       pci_write_config_dword(mac->dma_pdev,
+                              PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+                              PAS_DMA_RXCHAN_CCMDSTA_EN |
+                              PAS_DMA_RXCHAN_CCMDSTA_DU);
+
+       /* enable tx channel */
+       pci_write_config_dword(mac->dma_pdev,
+                              PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+                              PAS_DMA_TXCHAN_TCMDSTA_EN);
+
+       pasemi_mac_replenish_rx_ring(dev);
+
+       netif_start_queue(dev);
+       netif_poll_enable(dev);
+
+       ret = request_irq(mac->dma_pdev->irq + mac->dma_txch,
+                         &pasemi_mac_tx_intr, IRQF_DISABLED,
+                         mac->tx->irq_name, dev);
+       if (ret) {
+               dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
+                      mac->dma_pdev->irq + mac->dma_txch, ret);
+               goto out_tx_int;
+       }
+
+       ret = request_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch,
+                         &pasemi_mac_rx_intr, IRQF_DISABLED,
+                         mac->rx->irq_name, dev);
+       if (ret) {
+               dev_err(&mac->pdev->dev, "request_irq of irq %d failed: %d\n",
+                      mac->dma_pdev->irq + 20 + mac->dma_rxch, ret);
+               goto out_rx_int;
+       }
+
+       return 0;
+
+out_rx_int:
+       free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
+out_tx_int:
+       netif_poll_disable(dev);
+       netif_stop_queue(dev);
+       pasemi_mac_free_tx_resources(dev);
+out_tx_resources:
+       pasemi_mac_free_rx_resources(dev);
+out_rx_resources:
+
+       return ret;
+}
+
+#define MAX_RETRIES 5000
+
+static int pasemi_mac_close(struct net_device *dev)
+{
+       struct pasemi_mac *mac = netdev_priv(dev);
+       unsigned int stat;
+       int retries;
+
+       netif_stop_queue(dev);
+
+       /* Clean out any pending buffers */
+       pasemi_mac_clean_tx(mac);
+       pasemi_mac_clean_rx(mac, RX_RING_SIZE);
+
+       /* Disable interface */
+       pci_write_config_dword(mac->dma_pdev,
+                              PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+                              PAS_DMA_TXCHAN_TCMDSTA_ST);
+       pci_write_config_dword(mac->dma_pdev,
+                     PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+                     PAS_DMA_RXINT_RCMDSTA_ST);
+       pci_write_config_dword(mac->dma_pdev,
+                     PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+                     PAS_DMA_RXCHAN_CCMDSTA_ST);
+
+       for (retries = 0; retries < MAX_RETRIES; retries++) {
+               pci_read_config_dword(mac->dma_pdev,
+                                     PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch),
+                                     &stat);
+               if (stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)
+                       break;
+               cond_resched();
+       }
+
+       if (!(stat & PAS_DMA_TXCHAN_TCMDSTA_ACT)) {
+               dev_err(&mac->dma_pdev->dev, "Failed to stop tx channel\n");
+       }
+
+       for (retries = 0; retries < MAX_RETRIES; retries++) {
+               pci_read_config_dword(mac->dma_pdev,
+                                     PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch),
+                                     &stat);
+               if (stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)
+                       break;
+               cond_resched();
+       }
+
+       if (!(stat & PAS_DMA_RXCHAN_CCMDSTA_ACT)) {
+               dev_err(&mac->dma_pdev->dev, "Failed to stop rx channel\n");
+       }
+
+       for (retries = 0; retries < MAX_RETRIES; retries++) {
+               pci_read_config_dword(mac->dma_pdev,
+                                     PAS_DMA_RXINT_RCMDSTA(mac->dma_if),
+                                     &stat);
+               if (stat & PAS_DMA_RXINT_RCMDSTA_ACT)
+                       break;
+               cond_resched();
+       }
+
+       if (!(stat & PAS_DMA_RXINT_RCMDSTA_ACT)) {
+               dev_err(&mac->dma_pdev->dev, "Failed to stop rx interface\n");
+       }
+
+       /* Then, disable the channel. This must be done separately from
+        * stopping, since you can't disable when active.
+        */
+
+       pci_write_config_dword(mac->dma_pdev,
+                              PAS_DMA_TXCHAN_TCMDSTA(mac->dma_txch), 0);
+       pci_write_config_dword(mac->dma_pdev,
+                              PAS_DMA_RXCHAN_CCMDSTA(mac->dma_rxch), 0);
+       pci_write_config_dword(mac->dma_pdev,
+                              PAS_DMA_RXINT_RCMDSTA(mac->dma_if), 0);
+
+       free_irq(mac->dma_pdev->irq + mac->dma_txch, dev);
+       free_irq(mac->dma_pdev->irq + 20 + mac->dma_rxch, dev);
+
+       /* Free resources */
+       pasemi_mac_free_rx_resources(dev);
+       pasemi_mac_free_tx_resources(dev);
+
+       return 0;
+}
+
+static int pasemi_mac_start_tx(struct sk_buff *skb, struct net_device *dev)
+{
+       struct pasemi_mac *mac = netdev_priv(dev);
+       struct pasemi_mac_txring *txring;
+       struct pasemi_mac_buffer *info;
+       struct pas_dma_xct_descr *dp;
+       u64 dflags;
+       dma_addr_t map;
+       int flags;
+
+       dflags = XCT_MACTX_O | XCT_MACTX_ST | XCT_MACTX_SS | XCT_MACTX_CRC_PAD;
+
+       if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               switch (skb->nh.iph->protocol) {
+               case IPPROTO_TCP:
+                       dflags |= XCT_MACTX_CSUM_TCP;
+                       dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2);
+                       dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data);
+                       break;
+               case IPPROTO_UDP:
+                       dflags |= XCT_MACTX_CSUM_UDP;
+                       dflags |= XCT_MACTX_IPH((skb->h.raw - skb->nh.raw) >> 2);
+                       dflags |= XCT_MACTX_IPO(skb->nh.raw - skb->data);
+                       break;
+               }
+       }
+
+       map = pci_map_single(mac->dma_pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
+
+       if (dma_mapping_error(map))
+               return NETDEV_TX_BUSY;
+
+       txring = mac->tx;
+
+       spin_lock_irqsave(&txring->lock, flags);
+
+       if (txring->next_to_clean - txring->next_to_use == TX_RING_SIZE) {
+               spin_unlock_irqrestore(&txring->lock, flags);
+               pasemi_mac_clean_tx(mac);
+               spin_lock_irqsave(&txring->lock, flags);
+
+               if (txring->next_to_clean - txring->next_to_use ==
+                   TX_RING_SIZE) {
+                       /* Still no room -- stop the queue and wait for tx
+                        * intr when there's room.
+                        */
+                       netif_stop_queue(dev);
+                       goto out_err;
+               }
+       }
+
+
+       dp = &TX_DESC(mac, txring->next_to_use);
+       info = &TX_DESC_INFO(mac, txring->next_to_use);
+
+       dp->mactx = dflags | XCT_MACTX_LLEN(skb->len);
+       dp->ptr   = XCT_PTR_LEN(skb->len) | XCT_PTR_ADDR(map);
+       info->dma = map;
+       info->skb = skb;
+
+       txring->next_to_use++;
+       mac->stats.tx_packets++;
+       mac->stats.tx_bytes += skb->len;
+
+       spin_unlock_irqrestore(&txring->lock, flags);
+
+       pci_write_config_dword(mac->dma_pdev,
+                              PAS_DMA_TXCHAN_INCR(mac->dma_txch), 1);
+
+       return NETDEV_TX_OK;
+
+out_err:
+       spin_unlock_irqrestore(&txring->lock, flags);
+       pci_unmap_single(mac->dma_pdev, map, skb->len, PCI_DMA_TODEVICE);
+       return NETDEV_TX_BUSY;
+}
+
+static struct net_device_stats *pasemi_mac_get_stats(struct net_device *dev)
+{
+       struct pasemi_mac *mac = netdev_priv(dev);
+
+       return &mac->stats;
+}
+
+static void pasemi_mac_set_rx_mode(struct net_device *dev)
+{
+       struct pasemi_mac *mac = netdev_priv(dev);
+       unsigned int flags;
+
+       pci_read_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, &flags);
+
+       /* Set promiscuous */
+       if (dev->flags & IFF_PROMISC)
+               flags |= PAS_MAC_CFG_PCFG_PR;
+       else
+               flags &= ~PAS_MAC_CFG_PCFG_PR;
+
+       pci_write_config_dword(mac->pdev, PAS_MAC_CFG_PCFG, flags);
+}
+
+
+static int pasemi_mac_poll(struct net_device *dev, int *budget)
+{
+       int pkts, limit = min(*budget, dev->quota);
+       struct pasemi_mac *mac = netdev_priv(dev);
+
+       pkts = pasemi_mac_clean_rx(mac, limit);
+
+       if (pkts < limit) {
+               /* all done, no more packets present */
+               netif_rx_complete(dev);
+
+               /* re-enable receive interrupts */
+               pci_write_config_dword(mac->iob_pdev, PAS_IOB_DMA_COM_TIMEOUTCFG,
+                                      PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(1000000));
+               return 0;
+       } else {
+               /* used up our quantum, so reschedule */
+               dev->quota -= pkts;
+               *budget -= pkts;
+               return 1;
+       }
+}
+
+static int __devinit
+pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       static int index = 0;
+       struct net_device *dev;
+       struct pasemi_mac *mac;
+       int err;
+
+       err = pci_enable_device(pdev);
+       if (err)
+               return err;
+
+       dev = alloc_etherdev(sizeof(struct pasemi_mac));
+       if (dev == NULL) {
+               dev_err(&pdev->dev,
+                       "pasemi_mac: Could not allocate ethernet device.\n");
+               err = -ENOMEM;
+               goto out_disable_device;
+       }
+
+       SET_MODULE_OWNER(dev);
+       pci_set_drvdata(pdev, dev);
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       mac = netdev_priv(dev);
+
+       mac->pdev = pdev;
+       mac->netdev = dev;
+       mac->dma_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa007, NULL);
+
+       if (!mac->dma_pdev) {
+               dev_err(&pdev->dev, "Can't find DMA Controller\n");
+               err = -ENODEV;
+               goto out_free_netdev;
+       }
+
+       mac->iob_pdev = pci_get_device(PCI_VENDOR_ID_PASEMI, 0xa001, NULL);
+
+       if (!mac->iob_pdev) {
+               dev_err(&pdev->dev, "Can't find I/O Bridge\n");
+               err = -ENODEV;
+               goto out_put_dma_pdev;
+       }
+
+       /* These should come out of the device tree eventually */
+       mac->dma_txch = index;
+       mac->dma_rxch = index;
+
+       /* We probe GMAC before XAUI, but the DMA interfaces are
+        * in XAUI, GMAC order.
+        */
+       if (index < 4)
+               mac->dma_if = index + 2;
+       else
+               mac->dma_if = index - 4;
+       index++;
+
+       switch (pdev->device) {
+       case 0xa005:
+               mac->type = MAC_TYPE_GMAC;
+               break;
+       case 0xa006:
+               mac->type = MAC_TYPE_XAUI;
+               break;
+       default:
+               err = -ENODEV;
+               goto out;
+       }
+
+       /* get mac addr from device tree */
+       if (pasemi_get_mac_addr(mac) || !is_valid_ether_addr(mac->mac_addr)) {
+               err = -ENODEV;
+               goto out;
+       }
+       memcpy(dev->dev_addr, mac->mac_addr, sizeof(mac->mac_addr));
+
+       dev->open = pasemi_mac_open;
+       dev->stop = pasemi_mac_close;
+       dev->hard_start_xmit = pasemi_mac_start_tx;
+       dev->get_stats = pasemi_mac_get_stats;
+       dev->set_multicast_list = pasemi_mac_set_rx_mode;
+       dev->weight = 64;
+       dev->poll = pasemi_mac_poll;
+       dev->features = NETIF_F_HW_CSUM;
+
+       /* The dma status structure is located in the I/O bridge, and
+        * is cache coherent.
+        */
+       if (!dma_status)
+               /* XXXOJN This should come from the device tree */
+               dma_status = __ioremap(0xfd800000, 0x1000, 0);
+
+       mac->rx_status = &dma_status->rx_sta[mac->dma_rxch];
+       mac->tx_status = &dma_status->tx_sta[mac->dma_txch];
+
+       err = register_netdev(dev);
+
+       if (err) {
+               dev_err(&mac->pdev->dev, "register_netdev failed with error %d\n",
+                       err);
+               goto out;
+       } else
+               printk(KERN_INFO "%s: PA Semi %s: intf %d, txch %d, rxch %d, "
+                      "hw addr %02x:%02x:%02x:%02x:%02x:%02x\n",
+                      dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI",
+                      mac->dma_if, mac->dma_txch, mac->dma_rxch,
+                      dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
+                      dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+
+       return err;
+
+out:
+       pci_dev_put(mac->iob_pdev);
+out_put_dma_pdev:
+       pci_dev_put(mac->dma_pdev);
+out_free_netdev:
+       free_netdev(dev);
+out_disable_device:
+       pci_disable_device(pdev);
+       return err;
+
+}
+
+static void __devexit pasemi_mac_remove(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct pasemi_mac *mac;
+
+       if (!netdev)
+               return;
+
+       mac = netdev_priv(netdev);
+
+       unregister_netdev(netdev);
+
+       pci_disable_device(pdev);
+       pci_dev_put(mac->dma_pdev);
+       pci_dev_put(mac->iob_pdev);
+
+       pci_set_drvdata(pdev, NULL);
+       free_netdev(netdev);
+}
+
+static struct pci_device_id pasemi_mac_pci_tbl[] = {
+       { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa005) },
+       { PCI_DEVICE(PCI_VENDOR_ID_PASEMI, 0xa006) },
+};
+
+MODULE_DEVICE_TABLE(pci, pasemi_mac_pci_tbl);
+
+static struct pci_driver pasemi_mac_driver = {
+       .name           = "pasemi_mac",
+       .id_table       = pasemi_mac_pci_tbl,
+       .probe          = pasemi_mac_probe,
+       .remove         = __devexit_p(pasemi_mac_remove),
+};
+
+static void __exit pasemi_mac_cleanup_module(void)
+{
+       pci_unregister_driver(&pasemi_mac_driver);
+       __iounmap(dma_status);
+       dma_status = NULL;
+}
+
+int pasemi_mac_init_module(void)
+{
+       return pci_register_driver(&pasemi_mac_driver);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>");
+MODULE_DESCRIPTION("PA Semi PWRficient Ethernet driver");
+
+module_init(pasemi_mac_init_module);
+module_exit(pasemi_mac_cleanup_module);
diff --git a/drivers/net/pasemi_mac.h b/drivers/net/pasemi_mac.h
new file mode 100644 (file)
index 0000000..c3e37e4
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2006 PA Semi, Inc
+ *
+ * Driver for the PA6T-1682M onchip 1G/10G Ethernet MACs, soft state and
+ * hardware register layouts.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+#ifndef PASEMI_MAC_H
+#define PASEMI_MAC_H
+
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/spinlock.h>
+
+struct pasemi_mac_txring {
+       spinlock_t       lock;
+       struct pas_dma_xct_descr        *desc;
+       dma_addr_t       dma;
+       unsigned int     size;
+       unsigned int     next_to_use;
+       unsigned int     next_to_clean;
+       struct pasemi_mac_buffer *desc_info;
+       char             irq_name[10];  /* "eth%d tx" */
+};
+
+struct pasemi_mac_rxring {
+       spinlock_t       lock;
+       struct pas_dma_xct_descr        *desc;  /* RX channel descriptor ring */
+       dma_addr_t       dma;
+       u64             *buffers;       /* RX interface buffer ring */
+       dma_addr_t       buf_dma;
+       unsigned int     size;
+       unsigned int     next_to_fill;
+       unsigned int     next_to_clean;
+       struct pasemi_mac_buffer *desc_info;
+       char             irq_name[10];  /* "eth%d rx" */
+};
+
+struct pasemi_mac {
+       struct net_device *netdev;
+       struct pci_dev *pdev;
+       struct pci_dev *dma_pdev;
+       struct pci_dev *iob_pdev;
+       struct net_device_stats stats;
+
+       /* Pointer to the cacheable per-channel status registers */
+       u64     *rx_status;
+       u64     *tx_status;
+
+       u8              type;
+#define MAC_TYPE_GMAC  1
+#define MAC_TYPE_XAUI  2
+       u32     dma_txch;
+       u32     dma_if;
+       u32     dma_rxch;
+
+       u8              mac_addr[6];
+
+       struct timer_list       rxtimer;
+
+       struct pasemi_mac_txring *tx;
+       struct pasemi_mac_rxring *rx;
+};
+
+/* Software status descriptor (desc_info) */
+struct pasemi_mac_buffer {
+       struct sk_buff *skb;
+       dma_addr_t      dma;
+};
+
+
+/* status register layout in IOB region, at 0xfb800000 */
+struct pasdma_status {
+       u64 rx_sta[64];
+       u64 tx_sta[20];
+};
+
+/* descriptor structure */
+struct pas_dma_xct_descr {
+       union {
+               u64     mactx;
+               u64     macrx;
+       };
+       union {
+               u64     ptr;
+               u64     rxb;
+       };
+};
+
+/* MAC CFG register offsets */
+
+enum {
+       PAS_MAC_CFG_PCFG = 0x80,
+       PAS_MAC_CFG_TXP = 0x98,
+       PAS_MAC_IPC_CHNL = 0x208,
+};
+
+/* MAC CFG register fields */
+#define PAS_MAC_CFG_PCFG_PE            0x80000000
+#define PAS_MAC_CFG_PCFG_CE            0x40000000
+#define PAS_MAC_CFG_PCFG_BU            0x20000000
+#define PAS_MAC_CFG_PCFG_TT            0x10000000
+#define PAS_MAC_CFG_PCFG_TSR_M         0x0c000000
+#define PAS_MAC_CFG_PCFG_TSR_10M       0x00000000
+#define PAS_MAC_CFG_PCFG_TSR_100M      0x04000000
+#define PAS_MAC_CFG_PCFG_TSR_1G                0x08000000
+#define PAS_MAC_CFG_PCFG_TSR_10G       0x0c000000
+#define PAS_MAC_CFG_PCFG_T24           0x02000000
+#define PAS_MAC_CFG_PCFG_PR            0x01000000
+#define PAS_MAC_CFG_PCFG_CRO_M         0x00ff0000
+#define PAS_MAC_CFG_PCFG_CRO_S 16
+#define PAS_MAC_CFG_PCFG_IPO_M         0x0000ff00
+#define PAS_MAC_CFG_PCFG_IPO_S 8
+#define PAS_MAC_CFG_PCFG_S1            0x00000080
+#define PAS_MAC_CFG_PCFG_IO_M          0x00000060
+#define PAS_MAC_CFG_PCFG_IO_MAC                0x00000000
+#define PAS_MAC_CFG_PCFG_IO_OFF                0x00000020
+#define PAS_MAC_CFG_PCFG_IO_IND_ETH    0x00000040
+#define PAS_MAC_CFG_PCFG_IO_IND_IP     0x00000060
+#define PAS_MAC_CFG_PCFG_LP            0x00000010
+#define PAS_MAC_CFG_PCFG_TS            0x00000008
+#define PAS_MAC_CFG_PCFG_HD            0x00000004
+#define PAS_MAC_CFG_PCFG_SPD_M         0x00000003
+#define PAS_MAC_CFG_PCFG_SPD_10M       0x00000000
+#define PAS_MAC_CFG_PCFG_SPD_100M      0x00000001
+#define PAS_MAC_CFG_PCFG_SPD_1G                0x00000002
+#define PAS_MAC_CFG_PCFG_SPD_10G       0x00000003
+#define PAS_MAC_CFG_TXP_FCF            0x01000000
+#define PAS_MAC_CFG_TXP_FCE            0x00800000
+#define PAS_MAC_CFG_TXP_FC             0x00400000
+#define PAS_MAC_CFG_TXP_FPC_M          0x00300000
+#define PAS_MAC_CFG_TXP_FPC_S          20
+#define PAS_MAC_CFG_TXP_FPC(x)         (((x) << PAS_MAC_CFG_TXP_FPC_S) & \
+                                        PAS_MAC_CFG_TXP_FPC_M)
+#define PAS_MAC_CFG_TXP_RT             0x00080000
+#define PAS_MAC_CFG_TXP_BL             0x00040000
+#define PAS_MAC_CFG_TXP_SL_M           0x00030000
+#define PAS_MAC_CFG_TXP_SL_S           16
+#define PAS_MAC_CFG_TXP_SL(x)          (((x) << PAS_MAC_CFG_TXP_SL_S) & \
+                                        PAS_MAC_CFG_TXP_SL_M)
+#define PAS_MAC_CFG_TXP_COB_M          0x0000f000
+#define PAS_MAC_CFG_TXP_COB_S          12
+#define PAS_MAC_CFG_TXP_COB(x)         (((x) << PAS_MAC_CFG_TXP_COB_S) & \
+                                        PAS_MAC_CFG_TXP_COB_M)
+#define PAS_MAC_CFG_TXP_TIFT_M         0x00000f00
+#define PAS_MAC_CFG_TXP_TIFT_S         8
+#define PAS_MAC_CFG_TXP_TIFT(x)                (((x) << PAS_MAC_CFG_TXP_TIFT_S) & \
+                                        PAS_MAC_CFG_TXP_TIFT_M)
+#define PAS_MAC_CFG_TXP_TIFG_M         0x000000ff
+#define PAS_MAC_CFG_TXP_TIFG_S         0
+#define PAS_MAC_CFG_TXP_TIFG(x)                (((x) << PAS_MAC_CFG_TXP_TIFG_S) & \
+                                        PAS_MAC_CFG_TXP_TIFG_M)
+
+#define PAS_MAC_IPC_CHNL_DCHNO_M       0x003f0000
+#define PAS_MAC_IPC_CHNL_DCHNO_S       16
+#define PAS_MAC_IPC_CHNL_DCHNO(x)      (((x) << PAS_MAC_IPC_CHNL_DCHNO_S) & \
+                                        PAS_MAC_IPC_CHNL_DCHNO_M)
+#define PAS_MAC_IPC_CHNL_BCH_M         0x0000003f
+#define PAS_MAC_IPC_CHNL_BCH_S         0
+#define PAS_MAC_IPC_CHNL_BCH(x)                (((x) << PAS_MAC_IPC_CHNL_BCH_S) & \
+                                        PAS_MAC_IPC_CHNL_BCH_M)
+
+/* All these registers live in the PCI configuration space for the DMA PCI
+ * device. Use the normal PCI config access functions for them.
+ */
+enum {
+       PAS_DMA_COM_TXCMD = 0x100,      /* Transmit Command Register  */
+       PAS_DMA_COM_TXSTA = 0x104,      /* Transmit Status Register   */
+       PAS_DMA_COM_RXCMD = 0x108,      /* Receive Command Register   */
+       PAS_DMA_COM_RXSTA = 0x10c,      /* Receive Status Register    */
+};
+#define PAS_DMA_COM_TXCMD_EN   0x00000001 /* enable */
+#define PAS_DMA_COM_TXSTA_ACT  0x00000001 /* active */
+#define PAS_DMA_COM_RXCMD_EN   0x00000001 /* enable */
+#define PAS_DMA_COM_RXSTA_ACT  0x00000001 /* active */
+
+
+/* Per-interface and per-channel registers */
+#define _PAS_DMA_RXINT_STRIDE          0x20
+#define PAS_DMA_RXINT_RCMDSTA(i)       (0x200+(i)*_PAS_DMA_RXINT_STRIDE)
+#define    PAS_DMA_RXINT_RCMDSTA_EN    0x00000001
+#define    PAS_DMA_RXINT_RCMDSTA_ST    0x00000002
+#define    PAS_DMA_RXINT_RCMDSTA_OO    0x00000100
+#define    PAS_DMA_RXINT_RCMDSTA_BP    0x00000200
+#define    PAS_DMA_RXINT_RCMDSTA_DR    0x00000400
+#define    PAS_DMA_RXINT_RCMDSTA_BT    0x00000800
+#define    PAS_DMA_RXINT_RCMDSTA_TB    0x00001000
+#define    PAS_DMA_RXINT_RCMDSTA_ACT   0x00010000
+#define    PAS_DMA_RXINT_RCMDSTA_DROPS_M       0xfffe0000
+#define    PAS_DMA_RXINT_RCMDSTA_DROPS_S       17
+#define PAS_DMA_RXINT_INCR(i)          (0x210+(i)*_PAS_DMA_RXINT_STRIDE)
+#define    PAS_DMA_RXINT_INCR_INCR_M   0x0000ffff
+#define    PAS_DMA_RXINT_INCR_INCR_S   0
+#define    PAS_DMA_RXINT_INCR_INCR(x)  ((x) & 0x0000ffff)
+#define PAS_DMA_RXINT_BASEL(i)         (0x218+(i)*_PAS_DMA_RXINT_STRIDE)
+#define    PAS_DMA_RXINT_BASEL_BRBL(x) ((x) & ~0x3f)
+#define PAS_DMA_RXINT_BASEU(i)         (0x21c+(i)*_PAS_DMA_RXINT_STRIDE)
+#define    PAS_DMA_RXINT_BASEU_BRBH(x) ((x) & 0xfff)
+#define    PAS_DMA_RXINT_BASEU_SIZ_M   0x3fff0000      /* # of cache lines worth of buffer ring */
+#define    PAS_DMA_RXINT_BASEU_SIZ_S   16              /* 0 = 16K */
+#define    PAS_DMA_RXINT_BASEU_SIZ(x)  (((x) << PAS_DMA_RXINT_BASEU_SIZ_S) & \
+                                        PAS_DMA_RXINT_BASEU_SIZ_M)
+
+
+#define _PAS_DMA_TXCHAN_STRIDE 0x20    /* Size per channel             */
+#define _PAS_DMA_TXCHAN_TCMDSTA        0x300   /* Command / Status             */
+#define _PAS_DMA_TXCHAN_CFG    0x304   /* Configuration                */
+#define _PAS_DMA_TXCHAN_DSCRBU 0x308   /* Descriptor BU Allocation     */
+#define _PAS_DMA_TXCHAN_INCR   0x310   /* Descriptor increment         */
+#define _PAS_DMA_TXCHAN_CNT    0x314   /* Descriptor count/offset      */
+#define _PAS_DMA_TXCHAN_BASEL  0x318   /* Descriptor ring base (low)   */
+#define _PAS_DMA_TXCHAN_BASEU  0x31c   /*                      (high)  */
+#define PAS_DMA_TXCHAN_TCMDSTA(c) (0x300+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define    PAS_DMA_TXCHAN_TCMDSTA_EN   0x00000001      /* Enabled */
+#define    PAS_DMA_TXCHAN_TCMDSTA_ST   0x00000002      /* Stop interface */
+#define    PAS_DMA_TXCHAN_TCMDSTA_ACT  0x00010000      /* Active */
+#define PAS_DMA_TXCHAN_CFG(c)     (0x304+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define    PAS_DMA_TXCHAN_CFG_TY_IFACE 0x00000000      /* Type = interface */
+#define    PAS_DMA_TXCHAN_CFG_TATTR_M  0x0000003c
+#define    PAS_DMA_TXCHAN_CFG_TATTR_S  2
+#define    PAS_DMA_TXCHAN_CFG_TATTR(x) (((x) << PAS_DMA_TXCHAN_CFG_TATTR_S) & \
+                                        PAS_DMA_TXCHAN_CFG_TATTR_M)
+#define    PAS_DMA_TXCHAN_CFG_WT_M     0x000001c0
+#define    PAS_DMA_TXCHAN_CFG_WT_S     6
+#define    PAS_DMA_TXCHAN_CFG_WT(x)    (((x) << PAS_DMA_TXCHAN_CFG_WT_S) & \
+                                        PAS_DMA_TXCHAN_CFG_WT_M)
+#define    PAS_DMA_TXCHAN_CFG_CF       0x00001000      /* Clean first line */
+#define    PAS_DMA_TXCHAN_CFG_CL       0x00002000      /* Clean last line */
+#define    PAS_DMA_TXCHAN_CFG_UP       0x00004000      /* update tx descr when sent */
+#define PAS_DMA_TXCHAN_INCR(c)    (0x310+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define PAS_DMA_TXCHAN_BASEL(c)   (0x318+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define    PAS_DMA_TXCHAN_BASEL_BRBL_M 0xffffffc0
+#define    PAS_DMA_TXCHAN_BASEL_BRBL_S 0
+#define    PAS_DMA_TXCHAN_BASEL_BRBL(x)        (((x) << PAS_DMA_TXCHAN_BASEL_BRBL_S) & \
+                                        PAS_DMA_TXCHAN_BASEL_BRBL_M)
+#define PAS_DMA_TXCHAN_BASEU(c)   (0x31c+(c)*_PAS_DMA_TXCHAN_STRIDE)
+#define    PAS_DMA_TXCHAN_BASEU_BRBH_M 0x00000fff
+#define    PAS_DMA_TXCHAN_BASEU_BRBH_S 0
+#define    PAS_DMA_TXCHAN_BASEU_BRBH(x)        (((x) << PAS_DMA_TXCHAN_BASEU_BRBH_S) & \
+                                        PAS_DMA_TXCHAN_BASEU_BRBH_M)
+/* # of cache lines worth of buffer ring */
+#define    PAS_DMA_TXCHAN_BASEU_SIZ_M  0x3fff0000
+#define    PAS_DMA_TXCHAN_BASEU_SIZ_S  16              /* 0 = 16K */
+#define    PAS_DMA_TXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_TXCHAN_BASEU_SIZ_S) & \
+                                        PAS_DMA_TXCHAN_BASEU_SIZ_M)
+
+#define _PAS_DMA_RXCHAN_STRIDE 0x20    /* Size per channel             */
+#define _PAS_DMA_RXCHAN_CCMDSTA        0x800   /* Command / Status             */
+#define _PAS_DMA_RXCHAN_CFG    0x804   /* Configuration                */
+#define _PAS_DMA_RXCHAN_INCR   0x810   /* Descriptor increment         */
+#define _PAS_DMA_RXCHAN_CNT    0x814   /* Descriptor count/offset      */
+#define _PAS_DMA_RXCHAN_BASEL  0x818   /* Descriptor ring base (low)   */
+#define _PAS_DMA_RXCHAN_BASEU  0x81c   /*                      (high)  */
+#define PAS_DMA_RXCHAN_CCMDSTA(c) (0x800+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define    PAS_DMA_RXCHAN_CCMDSTA_EN   0x00000001      /* Enabled */
+#define    PAS_DMA_RXCHAN_CCMDSTA_ST   0x00000002      /* Stop interface */
+#define    PAS_DMA_RXCHAN_CCMDSTA_ACT  0x00010000      /* Active */
+#define    PAS_DMA_RXCHAN_CCMDSTA_DU   0x00020000
+#define PAS_DMA_RXCHAN_CFG(c)     (0x804+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define    PAS_DMA_RXCHAN_CFG_HBU_M    0x00000380
+#define    PAS_DMA_RXCHAN_CFG_HBU_S    7
+#define    PAS_DMA_RXCHAN_CFG_HBU(x)   (((x) << PAS_DMA_RXCHAN_CFG_HBU_S) & \
+                                        PAS_DMA_RXCHAN_CFG_HBU_M)
+#define PAS_DMA_RXCHAN_INCR(c)    (0x810+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define PAS_DMA_RXCHAN_BASEL(c)   (0x818+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define    PAS_DMA_RXCHAN_BASEL_BRBL_M 0xffffffc0
+#define    PAS_DMA_RXCHAN_BASEL_BRBL_S 0
+#define    PAS_DMA_RXCHAN_BASEL_BRBL(x)        (((x) << PAS_DMA_RXCHAN_BASEL_BRBL_S) & \
+                                        PAS_DMA_RXCHAN_BASEL_BRBL_M)
+#define PAS_DMA_RXCHAN_BASEU(c)   (0x81c+(c)*_PAS_DMA_RXCHAN_STRIDE)
+#define    PAS_DMA_RXCHAN_BASEU_BRBH_M 0x00000fff
+#define    PAS_DMA_RXCHAN_BASEU_BRBH_S 0
+#define    PAS_DMA_RXCHAN_BASEU_BRBH(x)        (((x) << PAS_DMA_RXCHAN_BASEU_BRBH_S) & \
+                                        PAS_DMA_RXCHAN_BASEU_BRBH_M)
+/* # of cache lines worth of buffer ring */
+#define    PAS_DMA_RXCHAN_BASEU_SIZ_M  0x3fff0000
+#define    PAS_DMA_RXCHAN_BASEU_SIZ_S  16              /* 0 = 16K */
+#define    PAS_DMA_RXCHAN_BASEU_SIZ(x) (((x) << PAS_DMA_RXCHAN_BASEU_SIZ_S) & \
+                                        PAS_DMA_RXCHAN_BASEU_SIZ_M)
+
+#define    PAS_STATUS_PCNT_M           0x000000000000ffffull
+#define    PAS_STATUS_PCNT_S           0
+#define    PAS_STATUS_DCNT_M           0x00000000ffff0000ull
+#define    PAS_STATUS_DCNT_S           16
+#define    PAS_STATUS_BPCNT_M          0x0000ffff00000000ull
+#define    PAS_STATUS_BPCNT_S          32
+#define    PAS_STATUS_TIMER            0x1000000000000000ull
+#define    PAS_STATUS_ERROR            0x2000000000000000ull
+#define    PAS_STATUS_SOFT             0x4000000000000000ull
+#define    PAS_STATUS_INT              0x8000000000000000ull
+
+#define PAS_IOB_DMA_RXCH_CFG(i)                (0x1100 + (i)*4)
+#define    PAS_IOB_DMA_RXCH_CFG_CNTTH_M                0x00000fff
+#define    PAS_IOB_DMA_RXCH_CFG_CNTTH_S                0
+#define    PAS_IOB_DMA_RXCH_CFG_CNTTH(x)       (((x) << PAS_IOB_DMA_RXCH_CFG_CNTTH_S) & \
+                                                PAS_IOB_DMA_RXCH_CFG_CNTTH_M)
+#define PAS_IOB_DMA_TXCH_CFG(i)                (0x1200 + (i)*4)
+#define    PAS_IOB_DMA_TXCH_CFG_CNTTH_M                0x00000fff
+#define    PAS_IOB_DMA_TXCH_CFG_CNTTH_S                0
+#define    PAS_IOB_DMA_TXCH_CFG_CNTTH(x)       (((x) << PAS_IOB_DMA_TXCH_CFG_CNTTH_S) & \
+                                                PAS_IOB_DMA_TXCH_CFG_CNTTH_M)
+#define PAS_IOB_DMA_RXCH_STAT(i)       (0x1300 + (i)*4)
+#define    PAS_IOB_DMA_RXCH_STAT_INTGEN        0x00001000
+#define    PAS_IOB_DMA_RXCH_STAT_CNTDEL_M      0x00000fff
+#define    PAS_IOB_DMA_RXCH_STAT_CNTDEL_S      0
+#define    PAS_IOB_DMA_RXCH_STAT_CNTDEL(x)     (((x) << PAS_IOB_DMA_RXCH_STAT_CNTDEL_S) &\
+                                                PAS_IOB_DMA_RXCH_STAT_CNTDEL_M)
+#define PAS_IOB_DMA_TXCH_STAT(i)       (0x1400 + (i)*4)
+#define    PAS_IOB_DMA_TXCH_STAT_INTGEN        0x00001000
+#define    PAS_IOB_DMA_TXCH_STAT_CNTDEL_M      0x00000fff
+#define    PAS_IOB_DMA_TXCH_STAT_CNTDEL_S      0
+#define    PAS_IOB_DMA_TXCH_STAT_CNTDEL(x)     (((x) << PAS_IOB_DMA_TXCH_STAT_CNTDEL_S) &\
+                                                PAS_IOB_DMA_TXCH_STAT_CNTDEL_M)
+#define PAS_IOB_DMA_RXCH_RESET(i)      (0x1500 + (i)*4)
+#define    PAS_IOB_DMA_RXCH_RESET_PCNT_M       0xffff0000
+#define    PAS_IOB_DMA_RXCH_RESET_PCNT_S       0
+#define    PAS_IOB_DMA_RXCH_RESET_PCNT(x)      (((x) << PAS_IOB_DMA_RXCH_RESET_PCNT_S) & \
+                                                PAS_IOB_DMA_RXCH_RESET_PCNT_M)
+#define    PAS_IOB_DMA_RXCH_RESET_PCNTRST      0x00000020
+#define    PAS_IOB_DMA_RXCH_RESET_DCNTRST      0x00000010
+#define    PAS_IOB_DMA_RXCH_RESET_TINTC                0x00000008
+#define    PAS_IOB_DMA_RXCH_RESET_DINTC                0x00000004
+#define    PAS_IOB_DMA_RXCH_RESET_SINTC                0x00000002
+#define    PAS_IOB_DMA_RXCH_RESET_PINTC                0x00000001
+#define PAS_IOB_DMA_TXCH_RESET(i)      (0x1600 + (i)*4)
+#define    PAS_IOB_DMA_TXCH_RESET_PCNT_M       0xffff0000
+#define    PAS_IOB_DMA_TXCH_RESET_PCNT_S       0
+#define    PAS_IOB_DMA_TXCH_RESET_PCNT(x)      (((x) << PAS_IOB_DMA_TXCH_RESET_PCNT_S) & \
+                                                PAS_IOB_DMA_TXCH_RESET_PCNT_M)
+#define    PAS_IOB_DMA_TXCH_RESET_PCNTRST      0x00000020
+#define    PAS_IOB_DMA_TXCH_RESET_DCNTRST      0x00000010
+#define    PAS_IOB_DMA_TXCH_RESET_TINTC                0x00000008
+#define    PAS_IOB_DMA_TXCH_RESET_DINTC                0x00000004
+#define    PAS_IOB_DMA_TXCH_RESET_SINTC                0x00000002
+#define    PAS_IOB_DMA_TXCH_RESET_PINTC                0x00000001
+
+#define PAS_IOB_DMA_COM_TIMEOUTCFG             0x1700
+#define    PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M   0x00ffffff
+#define    PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S   0
+#define    PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT(x)  (((x) << PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_S) & \
+                                                PAS_IOB_DMA_COM_TIMEOUTCFG_TCNT_M)
+
+/* Transmit descriptor fields */
+#define        XCT_MACTX_T             0x8000000000000000ull
+#define        XCT_MACTX_ST            0x4000000000000000ull
+#define XCT_MACTX_NORES                0x0000000000000000ull
+#define XCT_MACTX_8BRES                0x1000000000000000ull
+#define XCT_MACTX_24BRES       0x2000000000000000ull
+#define XCT_MACTX_40BRES       0x3000000000000000ull
+#define XCT_MACTX_I            0x0800000000000000ull
+#define XCT_MACTX_O            0x0400000000000000ull
+#define XCT_MACTX_E            0x0200000000000000ull
+#define XCT_MACTX_VLAN_M       0x0180000000000000ull
+#define XCT_MACTX_VLAN_NOP     0x0000000000000000ull
+#define XCT_MACTX_VLAN_REMOVE  0x0080000000000000ull
+#define XCT_MACTX_VLAN_INSERT   0x0100000000000000ull
+#define XCT_MACTX_VLAN_REPLACE  0x0180000000000000ull
+#define XCT_MACTX_CRC_M                0x0060000000000000ull
+#define XCT_MACTX_CRC_NOP      0x0000000000000000ull
+#define XCT_MACTX_CRC_INSERT   0x0020000000000000ull
+#define XCT_MACTX_CRC_PAD      0x0040000000000000ull
+#define XCT_MACTX_CRC_REPLACE  0x0060000000000000ull
+#define XCT_MACTX_SS           0x0010000000000000ull
+#define XCT_MACTX_LLEN_M       0x00007fff00000000ull
+#define XCT_MACTX_LLEN_S       32ull
+#define XCT_MACTX_LLEN(x)      ((((long)(x)) << XCT_MACTX_LLEN_S) & \
+                                XCT_MACTX_LLEN_M)
+#define XCT_MACTX_IPH_M                0x00000000f8000000ull
+#define XCT_MACTX_IPH_S                27ull
+#define XCT_MACTX_IPH(x)       ((((long)(x)) << XCT_MACTX_IPH_S) & \
+                                XCT_MACTX_IPH_M)
+#define XCT_MACTX_IPO_M                0x0000000007c00000ull
+#define XCT_MACTX_IPO_S                22ull
+#define XCT_MACTX_IPO(x)       ((((long)(x)) << XCT_MACTX_IPO_S) & \
+                                XCT_MACTX_IPO_M)
+#define XCT_MACTX_CSUM_M       0x0000000000000060ull
+#define XCT_MACTX_CSUM_NOP     0x0000000000000000ull
+#define XCT_MACTX_CSUM_TCP     0x0000000000000040ull
+#define XCT_MACTX_CSUM_UDP     0x0000000000000060ull
+#define XCT_MACTX_V6           0x0000000000000010ull
+#define XCT_MACTX_C            0x0000000000000004ull
+#define XCT_MACTX_AL2          0x0000000000000002ull
+
+/* Receive descriptor fields */
+#define        XCT_MACRX_T             0x8000000000000000ull
+#define        XCT_MACRX_ST            0x4000000000000000ull
+#define XCT_MACRX_NORES                0x0000000000000000ull
+#define XCT_MACRX_8BRES                0x1000000000000000ull
+#define XCT_MACRX_24BRES       0x2000000000000000ull
+#define XCT_MACRX_40BRES       0x3000000000000000ull
+#define XCT_MACRX_O            0x0400000000000000ull
+#define XCT_MACRX_E            0x0200000000000000ull
+#define XCT_MACRX_FF           0x0100000000000000ull
+#define XCT_MACRX_PF           0x0080000000000000ull
+#define XCT_MACRX_OB           0x0040000000000000ull
+#define XCT_MACRX_OD           0x0020000000000000ull
+#define XCT_MACRX_FS           0x0010000000000000ull
+#define XCT_MACRX_NB_M         0x000fc00000000000ull
+#define XCT_MACRX_NB_S         46ULL
+#define XCT_MACRX_NB(x)                ((((long)(x)) << XCT_MACRX_NB_S) & \
+                                XCT_MACRX_NB_M)
+#define XCT_MACRX_LLEN_M       0x00003fff00000000ull
+#define XCT_MACRX_LLEN_S       32ULL
+#define XCT_MACRX_LLEN(x)      ((((long)(x)) << XCT_MACRX_LLEN_S) & \
+                                XCT_MACRX_LLEN_M)
+#define XCT_MACRX_CRC          0x0000000080000000ull
+#define XCT_MACRX_LEN_M                0x0000000060000000ull
+#define XCT_MACRX_LEN_TOOSHORT 0x0000000020000000ull
+#define XCT_MACRX_LEN_BELOWMIN 0x0000000040000000ull
+#define XCT_MACRX_LEN_TRUNC    0x0000000060000000ull
+#define XCT_MACRX_CAST_M       0x0000000018000000ull
+#define XCT_MACRX_CAST_UNI     0x0000000000000000ull
+#define XCT_MACRX_CAST_MULTI   0x0000000008000000ull
+#define XCT_MACRX_CAST_BROAD   0x0000000010000000ull
+#define XCT_MACRX_CAST_PAUSE   0x0000000018000000ull
+#define XCT_MACRX_VLC_M                0x0000000006000000ull
+#define XCT_MACRX_FM           0x0000000001000000ull
+#define XCT_MACRX_HTY_M                0x0000000000c00000ull
+#define XCT_MACRX_HTY_IPV4_OK  0x0000000000000000ull
+#define XCT_MACRX_HTY_IPV6     0x0000000000400000ull
+#define XCT_MACRX_HTY_IPV4_BAD 0x0000000000800000ull
+#define XCT_MACRX_HTY_NONIP    0x0000000000c00000ull
+#define XCT_MACRX_IPP_M                0x00000000003f0000ull
+#define XCT_MACRX_IPP_S                16
+#define XCT_MACRX_CSUM_M       0x000000000000ffffull
+#define XCT_MACRX_CSUM_S       0
+
+#define XCT_PTR_T              0x8000000000000000ull
+#define XCT_PTR_LEN_M          0x7ffff00000000000ull
+#define XCT_PTR_LEN_S          44
+#define XCT_PTR_LEN(x)         ((((long)(x)) << XCT_PTR_LEN_S) & \
+                                XCT_PTR_LEN_M)
+#define XCT_PTR_ADDR_M         0x00000fffffffffffull
+#define XCT_PTR_ADDR_S         0
+#define XCT_PTR_ADDR(x)                ((((long)(x)) << XCT_PTR_ADDR_S) & \
+                                XCT_PTR_ADDR_M)
+
+/* Receive interface buffer fields */
+#define XCT_RXB_LEN_M          0x0ffff00000000000ull
+#define XCT_RXB_LEN_S          44
+#define XCT_RXB_LEN(x)         ((((long)(x)) << XCT_PTR_LEN_S) & XCT_PTR_LEN_M)
+#define XCT_RXB_ADDR_M         0x00000fffffffffffull
+#define XCT_RXB_ADDR_S         0
+#define XCT_RXB_ADDR(x)                ((((long)(x)) << XCT_PTR_ADDR_S) & XCT_PTR_ADDR_M)
+
+
+#endif /* PASEMI_MAC_H */
old mode 100644 (file)
new mode 100755 (executable)
index 8844c20..2429b27
@@ -22,6 +22,7 @@
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/ip.h>
+#include <linux/in.h>
 #include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/netdevice.h>
@@ -63,6 +64,7 @@ MODULE_PARM_DESC(msi, "Turn on Message Signaled Interrupts.");
 
 static struct pci_device_id ql3xxx_pci_tbl[] __devinitdata = {
        {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3022_DEVICE_ID)},
+       {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QL3032_DEVICE_ID)},
        /* required last entry */
        {0,}
 };
@@ -1475,6 +1477,10 @@ static int ql_mii_setup(struct ql3_adapter *qdev)
                         2) << 7))
                return -1;
 
+       if (qdev->device_id == QL3032_DEVICE_ID)
+               ql_write_page0_reg(qdev, 
+                       &port_regs->macMIIMgmtControlReg, 0x0f00000);
+
        /* Divide 125MHz clock by 28 to meet PHY timing requirements */
        reg = MAC_MII_CONTROL_CLK_SEL_DIV28;
 
@@ -1706,18 +1712,42 @@ static void ql_process_mac_tx_intr(struct ql3_adapter *qdev,
                                   struct ob_mac_iocb_rsp *mac_rsp)
 {
        struct ql_tx_buf_cb *tx_cb;
+       int i;
 
        tx_cb = &qdev->tx_buf[mac_rsp->transaction_id];
        pci_unmap_single(qdev->pdev,
-                        pci_unmap_addr(tx_cb, mapaddr),
-                        pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
-       dev_kfree_skb_irq(tx_cb->skb);
+                        pci_unmap_addr(&tx_cb->map[0], mapaddr),
+                        pci_unmap_len(&tx_cb->map[0], maplen),
+                        PCI_DMA_TODEVICE);
+       tx_cb->seg_count--;
+       if (tx_cb->seg_count) {
+               for (i = 1; i < tx_cb->seg_count; i++) {
+                       pci_unmap_page(qdev->pdev,
+                                      pci_unmap_addr(&tx_cb->map[i],
+                                                     mapaddr),
+                                      pci_unmap_len(&tx_cb->map[i], maplen),
+                                      PCI_DMA_TODEVICE);
+               }
+       }
        qdev->stats.tx_packets++;
        qdev->stats.tx_bytes += tx_cb->skb->len;
+       dev_kfree_skb_irq(tx_cb->skb);
        tx_cb->skb = NULL;
        atomic_inc(&qdev->tx_count);
 }
 
+/*
+ * The difference between 3022 and 3032 for inbound completions:
+ * 3022 uses two buffers per completion.  The first buffer contains 
+ * (some) header info, the second the remainder of the headers plus 
+ * the data.  For this chip we reserve some space at the top of the 
+ * receive buffer so that the header info in buffer one can be 
+ * prepended to the buffer two.  Buffer two is the sent up while 
+ * buffer one is returned to the hardware to be reused.
+ * 3032 receives all of it's data and headers in one buffer for a 
+ * simpler process.  3032 also supports checksum verification as
+ * can be seen in ql_process_macip_rx_intr().
+ */
 static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
                                   struct ib_mac_iocb_rsp *ib_mac_rsp_ptr)
 {
@@ -1740,14 +1770,17 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
        qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
        qdev->small_buf_release_cnt++;
 
-       /* start of first buffer */
-       lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
-       lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
-       qdev->lrg_buf_release_cnt++;
-       if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
-               qdev->lrg_buf_index = 0;
-       curr_ial_ptr++;         /* 64-bit pointers require two incs. */
-       curr_ial_ptr++;
+       if (qdev->device_id == QL3022_DEVICE_ID) {
+               /* start of first buffer (3022 only) */
+               lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+               lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+               qdev->lrg_buf_release_cnt++;
+               if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS) {
+                       qdev->lrg_buf_index = 0;
+               }
+               curr_ial_ptr++; /* 64-bit pointers require two incs. */
+               curr_ial_ptr++;
+       }
 
        /* start of second buffer */
        lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
@@ -1778,7 +1811,8 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev,
        qdev->ndev->last_rx = jiffies;
        lrg_buf_cb2->skb = NULL;
 
-       ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+       if (qdev->device_id == QL3022_DEVICE_ID)
+               ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
        ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
 }
 
@@ -1790,7 +1824,7 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
        struct ql_rcv_buf_cb *lrg_buf_cb1 = NULL;
        struct ql_rcv_buf_cb *lrg_buf_cb2 = NULL;
        u32 *curr_ial_ptr;
-       struct sk_buff *skb1, *skb2;
+       struct sk_buff *skb1 = NULL, *skb2;
        struct net_device *ndev = qdev->ndev;
        u16 length = le16_to_cpu(ib_ip_rsp_ptr->length);
        u16 size = 0;
@@ -1806,16 +1840,20 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
        qdev->last_rsp_offset = qdev->small_buf_phy_addr_low + offset;
        qdev->small_buf_release_cnt++;
 
-       /* start of first buffer */
-       lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
-       lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
-
-       qdev->lrg_buf_release_cnt++;
-       if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
-               qdev->lrg_buf_index = 0;
-       skb1 = lrg_buf_cb1->skb;
-       curr_ial_ptr++;         /* 64-bit pointers require two incs. */
-       curr_ial_ptr++;
+       if (qdev->device_id == QL3022_DEVICE_ID) {
+               /* start of first buffer on 3022 */
+               lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
+               lrg_buf_cb1 = &qdev->lrg_buf[qdev->lrg_buf_index];
+               qdev->lrg_buf_release_cnt++;
+               if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
+                       qdev->lrg_buf_index = 0;
+               skb1 = lrg_buf_cb1->skb;
+               curr_ial_ptr++; /* 64-bit pointers require two incs. */
+               curr_ial_ptr++;
+               size = ETH_HLEN;
+               if (*((u16 *) skb1->data) != 0xFFFF)
+                       size += VLAN_ETH_HLEN - ETH_HLEN;
+       }
 
        /* start of second buffer */
        lrg_buf_phy_addr_low = le32_to_cpu(*curr_ial_ptr);
@@ -1825,18 +1863,6 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
        if (++qdev->lrg_buf_index == NUM_LARGE_BUFFERS)
                qdev->lrg_buf_index = 0;
 
-       qdev->stats.rx_packets++;
-       qdev->stats.rx_bytes += length;
-
-       /*
-        * Copy the ethhdr from first buffer to second. This
-        * is necessary for IP completions.
-        */
-       if (*((u16 *) skb1->data) != 0xFFFF)
-               size = VLAN_ETH_HLEN;
-       else
-               size = ETH_HLEN;
-
        skb_put(skb2, length);  /* Just the second buffer length here. */
        pci_unmap_single(qdev->pdev,
                         pci_unmap_addr(lrg_buf_cb2, mapaddr),
@@ -1844,16 +1870,40 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev,
                         PCI_DMA_FROMDEVICE);
        prefetch(skb2->data);
 
-       memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
-       skb2->dev = qdev->ndev;
        skb2->ip_summed = CHECKSUM_NONE;
+       if (qdev->device_id == QL3022_DEVICE_ID) {
+               /*
+                * Copy the ethhdr from first buffer to second. This
+                * is necessary for 3022 IP completions.
+                */
+               memcpy(skb_push(skb2, size), skb1->data + VLAN_ID_LEN, size);
+       } else {
+               u16 checksum = le16_to_cpu(ib_ip_rsp_ptr->checksum);
+               if (checksum & 
+                       (IB_IP_IOCB_RSP_3032_ICE | 
+                        IB_IP_IOCB_RSP_3032_CE | 
+                        IB_IP_IOCB_RSP_3032_NUC)) {
+                       printk(KERN_ERR
+                              "%s: Bad checksum for this %s packet, checksum = %x.\n",
+                              __func__,
+                              ((checksum & 
+                               IB_IP_IOCB_RSP_3032_TCP) ? "TCP" :
+                               "UDP"),checksum);
+               } else if (checksum & IB_IP_IOCB_RSP_3032_TCP) {
+                       skb2->ip_summed = CHECKSUM_UNNECESSARY;
+               } 
+       }
+       skb2->dev = qdev->ndev;
        skb2->protocol = eth_type_trans(skb2, qdev->ndev);
 
        netif_receive_skb(skb2);
+       qdev->stats.rx_packets++;
+       qdev->stats.rx_bytes += length;
        ndev->last_rx = jiffies;
        lrg_buf_cb2->skb = NULL;
 
-       ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
+       if (qdev->device_id == QL3022_DEVICE_ID)
+               ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb1);
        ql_release_to_lrg_buf_free_list(qdev, lrg_buf_cb2);
 }
 
@@ -1880,12 +1930,14 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev,
                        break;
 
                case OPCODE_IB_MAC_IOCB:
+               case OPCODE_IB_3032_MAC_IOCB:
                        ql_process_mac_rx_intr(qdev, (struct ib_mac_iocb_rsp *)
                                               net_rsp);
                        (*rx_cleaned)++;
                        break;
 
                case OPCODE_IB_IP_IOCB:
+               case OPCODE_IB_3032_IP_IOCB:
                        ql_process_macip_rx_intr(qdev, (struct ib_ip_iocb_rsp *)
                                                 net_rsp);
                        (*rx_cleaned)++;
@@ -2032,13 +2084,96 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id)
        return IRQ_RETVAL(handled);
 }
 
+/*
+ * Get the total number of segments needed for the 
+ * given number of fragments.  This is necessary because
+ * outbound address lists (OAL) will be used when more than
+ * two frags are given.  Each address list has 5 addr/len 
+ * pairs.  The 5th pair in each AOL is used to  point to
+ * the next AOL if more frags are coming.  
+ * That is why the frags:segment count  ratio is not linear.
+ */
+static int ql_get_seg_count(unsigned short frags)
+{
+       switch(frags) {
+       case 0: return 1;       /* just the skb->data seg */
+       case 1: return 2;       /* skb->data + 1 frag */
+       case 2: return 3;       /* skb->data + 2 frags */
+       case 3: return 5;       /* skb->data + 1 frag + 1 AOL containting 2 frags */
+       case 4: return 6;
+       case 5: return 7;
+       case 6: return 8;
+       case 7: return 10;
+       case 8: return 11;
+       case 9: return 12;
+       case 10: return 13;
+       case 11: return 15;
+       case 12: return 16;
+       case 13: return 17;
+       case 14: return 18;
+       case 15: return 20;
+       case 16: return 21;
+       case 17: return 22;
+       case 18: return 23;
+       }
+       return -1;
+}
+
+static void ql_hw_csum_setup(struct sk_buff *skb,
+                            struct ob_mac_iocb_req *mac_iocb_ptr)
+{
+       struct ethhdr *eth;
+       struct iphdr *ip = NULL;
+       u8 offset = ETH_HLEN;
+
+       eth = (struct ethhdr *)(skb->data);
+
+       if (eth->h_proto == __constant_htons(ETH_P_IP)) {
+               ip = (struct iphdr *)&skb->data[ETH_HLEN];
+       } else if (eth->h_proto == htons(ETH_P_8021Q) &&
+                  ((struct vlan_ethhdr *)skb->data)->
+                  h_vlan_encapsulated_proto == __constant_htons(ETH_P_IP)) {
+               ip = (struct iphdr *)&skb->data[VLAN_ETH_HLEN];
+               offset = VLAN_ETH_HLEN;
+       }
+
+       if (ip) {
+               if (ip->protocol == IPPROTO_TCP) {
+                       mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_TC;
+                       mac_iocb_ptr->ip_hdr_off = offset;
+                       mac_iocb_ptr->ip_hdr_len = ip->ihl;
+               } else if (ip->protocol == IPPROTO_UDP) {
+                       mac_iocb_ptr->flags1 |= OB_3032MAC_IOCB_REQ_UC;
+                       mac_iocb_ptr->ip_hdr_off = offset;
+                       mac_iocb_ptr->ip_hdr_len = ip->ihl;
+               }
+       }
+}
+
+/*
+ * The difference between 3022 and 3032 sends:
+ * 3022 only supports a simple single segment transmission.
+ * 3032 supports checksumming and scatter/gather lists (fragments).
+ * The 3032 supports sglists by using the 3 addr/len pairs (ALP) 
+ * in the IOCB plus a chain of outbound address lists (OAL) that 
+ * each contain 5 ALPs.  The last ALP of the IOCB (3rd) or OAL (5th) 
+ * will used to point to an OAL when more ALP entries are required.  
+ * The IOCB is always the top of the chain followed by one or more 
+ * OALs (when necessary).
+ */
 static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
 {
        struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev);
        struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers;
        struct ql_tx_buf_cb *tx_cb;
+       u32 tot_len = skb->len;
+       struct oal *oal;
+       struct oal_entry *oal_entry;
+       int len;
        struct ob_mac_iocb_req *mac_iocb_ptr;
        u64 map;
+       int seg_cnt, seg = 0;
+       int frag_cnt = (int)skb_shinfo(skb)->nr_frags;
 
        if (unlikely(atomic_read(&qdev->tx_count) < 2)) {
                if (!netif_queue_stopped(ndev))
@@ -2046,21 +2181,79 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
                return NETDEV_TX_BUSY;
        }
        tx_cb = &qdev->tx_buf[qdev->req_producer_index] ;
+       seg_cnt = tx_cb->seg_count = ql_get_seg_count((skb_shinfo(skb)->nr_frags));
+       if(seg_cnt == -1) {
+               printk(KERN_ERR PFX"%s: invalid segment count!\n",__func__);
+               return NETDEV_TX_OK;
+
+       }
        mac_iocb_ptr = tx_cb->queue_entry;
        memset((void *)mac_iocb_ptr, 0, sizeof(struct ob_mac_iocb_req));
        mac_iocb_ptr->opcode = qdev->mac_ob_opcode;
        mac_iocb_ptr->flags |= qdev->mb_bit_mask;
        mac_iocb_ptr->transaction_id = qdev->req_producer_index;
-       mac_iocb_ptr->data_len = cpu_to_le16((u16) skb->len);
+       mac_iocb_ptr->data_len = cpu_to_le16((u16) tot_len);
        tx_cb->skb = skb;
-       map = pci_map_single(qdev->pdev, skb->data, skb->len, PCI_DMA_TODEVICE);
-       mac_iocb_ptr->buf_addr0_low = cpu_to_le32(LS_64BITS(map));
-       mac_iocb_ptr->buf_addr0_high = cpu_to_le32(MS_64BITS(map));
-       mac_iocb_ptr->buf_0_len = cpu_to_le32(skb->len | OB_MAC_IOCB_REQ_E);
-       pci_unmap_addr_set(tx_cb, mapaddr, map);
-       pci_unmap_len_set(tx_cb, maplen, skb->len);
-       atomic_dec(&qdev->tx_count);
+       if (skb->ip_summed == CHECKSUM_PARTIAL)
+               ql_hw_csum_setup(skb, mac_iocb_ptr);
+       len = skb_headlen(skb);
+       map = pci_map_single(qdev->pdev, skb->data, len, PCI_DMA_TODEVICE);
+       oal_entry = (struct oal_entry *)&mac_iocb_ptr->buf_addr0_low;
+       oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+       oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+       oal_entry->len = cpu_to_le32(len);
+       pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+       pci_unmap_len_set(&tx_cb->map[seg], maplen, len);
+       seg++;
+
+       if (!skb_shinfo(skb)->nr_frags) {
+               /* Terminate the last segment. */
+               oal_entry->len =
+                   cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
+       } else {
+               int i;
+               oal = tx_cb->oal;
+               for (i=0; i<frag_cnt; i++,seg++) {
+                       skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+                       oal_entry++;
+                       if ((seg == 2 && seg_cnt > 3) ||        /* Check for continuation */
+                           (seg == 7 && seg_cnt > 8) ||        /* requirements. It's strange */
+                           (seg == 12 && seg_cnt > 13) ||      /* but necessary. */
+                           (seg == 17 && seg_cnt > 18)) {
+                               /* Continuation entry points to outbound address list. */
+                               map = pci_map_single(qdev->pdev, oal,
+                                                    sizeof(struct oal),
+                                                    PCI_DMA_TODEVICE);
+                               oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+                               oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+                               oal_entry->len =
+                                   cpu_to_le32(sizeof(struct oal) |
+                                               OAL_CONT_ENTRY);
+                               pci_unmap_addr_set(&tx_cb->map[seg], mapaddr,
+                                                  map);
+                               pci_unmap_len_set(&tx_cb->map[seg], maplen,
+                                                 len);
+                               oal_entry = (struct oal_entry *)oal;
+                               oal++;
+                               seg++;
+                       }
 
+                       map =
+                           pci_map_page(qdev->pdev, frag->page,
+                                        frag->page_offset, frag->size,
+                                        PCI_DMA_TODEVICE);
+                       oal_entry->dma_lo = cpu_to_le32(LS_64BITS(map));
+                       oal_entry->dma_hi = cpu_to_le32(MS_64BITS(map));
+                       oal_entry->len = cpu_to_le32(frag->size);
+                       pci_unmap_addr_set(&tx_cb->map[seg], mapaddr, map);
+                       pci_unmap_len_set(&tx_cb->map[seg], maplen,
+                                         frag->size);
+               }
+               /* Terminate the last segment. */
+               oal_entry->len =
+                   cpu_to_le32(le32_to_cpu(oal_entry->len) | OAL_LAST_ENTRY);
+       }
+       wmb();
        qdev->req_producer_index++;
        if (qdev->req_producer_index == NUM_REQ_Q_ENTRIES)
                qdev->req_producer_index = 0;
@@ -2074,8 +2267,10 @@ static int ql3xxx_send(struct sk_buff *skb, struct net_device *ndev)
                printk(KERN_DEBUG PFX "%s: tx queued, slot %d, len %d\n",
                       ndev->name, qdev->req_producer_index, skb->len);
 
+       atomic_dec(&qdev->tx_count);
        return NETDEV_TX_OK;
 }
+
 static int ql_alloc_net_req_rsp_queues(struct ql3_adapter *qdev)
 {
        qdev->req_q_size =
@@ -2359,7 +2554,22 @@ static int ql_alloc_large_buffers(struct ql3_adapter *qdev)
        return 0;
 }
 
-static void ql_create_send_free_list(struct ql3_adapter *qdev)
+static void ql_free_send_free_list(struct ql3_adapter *qdev)
+{
+       struct ql_tx_buf_cb *tx_cb;
+       int i;
+
+       tx_cb = &qdev->tx_buf[0];
+       for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+               if (tx_cb->oal) {
+                       kfree(tx_cb->oal);
+                       tx_cb->oal = NULL;
+               }
+               tx_cb++;
+       }
+}
+
+static int ql_create_send_free_list(struct ql3_adapter *qdev)
 {
        struct ql_tx_buf_cb *tx_cb;
        int i;
@@ -2368,11 +2578,16 @@ static void ql_create_send_free_list(struct ql3_adapter *qdev)
 
        /* Create free list of transmit buffers */
        for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+
                tx_cb = &qdev->tx_buf[i];
                tx_cb->skb = NULL;
                tx_cb->queue_entry = req_q_curr;
                req_q_curr++;
+               tx_cb->oal = kmalloc(512, GFP_KERNEL);
+               if (tx_cb->oal == NULL)
+                       return -1;
        }
+       return 0;
 }
 
 static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
@@ -2447,12 +2662,14 @@ static int ql_alloc_mem_resources(struct ql3_adapter *qdev)
 
        /* Initialize the large buffer queue. */
        ql_init_large_buffers(qdev);
-       ql_create_send_free_list(qdev);
+       if (ql_create_send_free_list(qdev))
+               goto err_free_list;
 
        qdev->rsp_current = qdev->rsp_q_virt_addr;
 
        return 0;
-
+err_free_list:
+       ql_free_send_free_list(qdev);
 err_small_buffers:
        ql_free_buffer_queues(qdev);
 err_buffer_queues:
@@ -2468,6 +2685,7 @@ err_req_rsp:
 
 static void ql_free_mem_resources(struct ql3_adapter *qdev)
 {
+       ql_free_send_free_list(qdev);
        ql_free_large_buffers(qdev);
        ql_free_small_buffers(qdev);
        ql_free_buffer_queues(qdev);
@@ -2766,11 +2984,20 @@ static int ql_adapter_initialize(struct ql3_adapter *qdev)
        }
 
        /* Enable Ethernet Function */
-       value =
-           (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
-            PORT_CONTROL_HH);
-       ql_write_page0_reg(qdev, &port_regs->portControl,
-                          ((value << 16) | value));
+       if (qdev->device_id == QL3032_DEVICE_ID) {
+               value =
+                   (QL3032_PORT_CONTROL_EF | QL3032_PORT_CONTROL_KIE |
+                    QL3032_PORT_CONTROL_EIv6 | QL3032_PORT_CONTROL_EIv4);
+               ql_write_page0_reg(qdev, &port_regs->functionControl,
+                                  ((value << 16) | value));
+       } else {
+               value =
+                   (PORT_CONTROL_EF | PORT_CONTROL_ET | PORT_CONTROL_EI |
+                    PORT_CONTROL_HH);
+               ql_write_page0_reg(qdev, &port_regs->portControl,
+                                  ((value << 16) | value));
+       }
+
 
 out:
        return status;
@@ -2917,8 +3144,10 @@ static void ql_display_dev_info(struct net_device *ndev)
        struct pci_dev *pdev = qdev->pdev;
 
        printk(KERN_INFO PFX
-              "\n%s Adapter %d RevisionID %d found on PCI slot %d.\n",
-              DRV_NAME, qdev->index, qdev->chip_rev_id, qdev->pci_slot);
+              "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n",
+              DRV_NAME, qdev->index, qdev->chip_rev_id,
+              (qdev->device_id == QL3032_DEVICE_ID) ? "QLA3032" : "QLA3022",
+              qdev->pci_slot);
        printk(KERN_INFO PFX
               "%s Interface.\n",
               test_bit(QL_LINK_OPTICAL,&qdev->flags) ? "OPTICAL" : "COPPER");
@@ -3212,15 +3441,22 @@ static void ql_reset_work(struct work_struct *work)
                 * Loop through the active list and return the skb.
                 */
                for (i = 0; i < NUM_REQ_Q_ENTRIES; i++) {
+                       int j;
                        tx_cb = &qdev->tx_buf[i];
                        if (tx_cb->skb) {
-
                                printk(KERN_DEBUG PFX
                                       "%s: Freeing lost SKB.\n",
                                       qdev->ndev->name);
                                pci_unmap_single(qdev->pdev,
-                                       pci_unmap_addr(tx_cb, mapaddr),
-                                       pci_unmap_len(tx_cb, maplen), PCI_DMA_TODEVICE);
+                                        pci_unmap_addr(&tx_cb->map[0], mapaddr),
+                                        pci_unmap_len(&tx_cb->map[0], maplen),
+                                        PCI_DMA_TODEVICE);
+                               for(j=1;j<tx_cb->seg_count;j++) {
+                                       pci_unmap_page(qdev->pdev,
+                                              pci_unmap_addr(&tx_cb->map[j],mapaddr),
+                                              pci_unmap_len(&tx_cb->map[j],maplen),
+                                              PCI_DMA_TODEVICE);
+                               }
                                dev_kfree_skb(tx_cb->skb);
                                tx_cb->skb = NULL;
                        }
@@ -3379,21 +3615,24 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev,
        SET_MODULE_OWNER(ndev);
        SET_NETDEV_DEV(ndev, &pdev->dev);
 
-       if (pci_using_dac)
-               ndev->features |= NETIF_F_HIGHDMA;
-
        pci_set_drvdata(pdev, ndev);
 
        qdev = netdev_priv(ndev);
        qdev->index = cards_found;
        qdev->ndev = ndev;
        qdev->pdev = pdev;
+       qdev->device_id = pci_entry->device;
        qdev->port_link_state = LS_DOWN;
        if (msi)
                qdev->msi = 1;
 
        qdev->msg_enable = netif_msg_init(debug, default_msg);
 
+       if (pci_using_dac)
+               ndev->features |= NETIF_F_HIGHDMA;
+       if (qdev->device_id == QL3032_DEVICE_ID)
+               ndev->features |= (NETIF_F_HW_CSUM | NETIF_F_SG);
+
        qdev->mem_map_registers =
            ioremap_nocache(pci_resource_start(pdev, 1),
                            pci_resource_len(qdev->pdev, 1));
old mode 100644 (file)
new mode 100755 (executable)
index ea94de7..b2d76ea
@@ -21,7 +21,9 @@
 
 #define OPCODE_UPDATE_NCB_IOCB      0xF0
 #define OPCODE_IB_MAC_IOCB          0xF9
+#define OPCODE_IB_3032_MAC_IOCB     0x09
 #define OPCODE_IB_IP_IOCB           0xFA
+#define OPCODE_IB_3032_IP_IOCB      0x0A
 #define OPCODE_IB_TCP_IOCB          0xFB
 #define OPCODE_DUMP_PROTO_IOCB      0xFE
 #define OPCODE_BUFFER_ALERT_IOCB    0xFB
 struct ob_mac_iocb_req {
        u8 opcode;
        u8 flags;
-#define OB_MAC_IOCB_REQ_MA  0xC0
-#define OB_MAC_IOCB_REQ_F   0x20
-#define OB_MAC_IOCB_REQ_X   0x10
+#define OB_MAC_IOCB_REQ_MA  0xe0
+#define OB_MAC_IOCB_REQ_F   0x10
+#define OB_MAC_IOCB_REQ_X   0x08
 #define OB_MAC_IOCB_REQ_D   0x02
 #define OB_MAC_IOCB_REQ_I   0x01
-       __le16 reserved0;
+       u8 flags1;
+#define OB_3032MAC_IOCB_REQ_IC 0x04
+#define OB_3032MAC_IOCB_REQ_TC 0x02
+#define OB_3032MAC_IOCB_REQ_UC 0x01
+       u8 reserved0;
 
        __le32 transaction_id;
        __le16 data_len;
-       __le16 reserved1;
+       u8 ip_hdr_off;
+       u8 ip_hdr_len;
+       __le32 reserved1;
        __le32 reserved2;
-       __le32 reserved3;
        __le32 buf_addr0_low;
        __le32 buf_addr0_high;
        __le32 buf_0_len;
@@ -58,8 +65,8 @@ struct ob_mac_iocb_req {
        __le32 buf_addr2_low;
        __le32 buf_addr2_high;
        __le32 buf_2_len;
+       __le32 reserved3;
        __le32 reserved4;
-       __le32 reserved5;
 };
 /*
  * The following constants define control bits for buffer
@@ -74,6 +81,7 @@ struct ob_mac_iocb_rsp {
        u8 opcode;
        u8 flags;
 #define OB_MAC_IOCB_RSP_P   0x08
+#define OB_MAC_IOCB_RSP_L   0x04
 #define OB_MAC_IOCB_RSP_S   0x02
 #define OB_MAC_IOCB_RSP_I   0x01
 
@@ -85,6 +93,7 @@ struct ob_mac_iocb_rsp {
 
 struct ib_mac_iocb_rsp {
        u8 opcode;
+#define IB_MAC_IOCB_RSP_V   0x80
        u8 flags;
 #define IB_MAC_IOCB_RSP_S   0x80
 #define IB_MAC_IOCB_RSP_H1  0x40
@@ -138,6 +147,7 @@ struct ob_ip_iocb_req {
 struct ob_ip_iocb_rsp {
        u8 opcode;
        u8 flags;
+#define OB_MAC_IOCB_RSP_H       0x10
 #define OB_MAC_IOCB_RSP_E       0x08
 #define OB_MAC_IOCB_RSP_L       0x04
 #define OB_MAC_IOCB_RSP_S       0x02
@@ -220,6 +230,10 @@ struct ob_tcp_iocb_rsp {
 
 struct ib_ip_iocb_rsp {
        u8 opcode;
+#define IB_IP_IOCB_RSP_3032_V   0x80
+#define IB_IP_IOCB_RSP_3032_O   0x40
+#define IB_IP_IOCB_RSP_3032_I   0x20
+#define IB_IP_IOCB_RSP_3032_R   0x10
        u8 flags;
 #define IB_IP_IOCB_RSP_S        0x80
 #define IB_IP_IOCB_RSP_H1       0x40
@@ -230,6 +244,12 @@ struct ib_ip_iocb_rsp {
 
        __le16 length;
        __le16 checksum;
+#define IB_IP_IOCB_RSP_3032_ICE                0x01
+#define IB_IP_IOCB_RSP_3032_CE         0x02
+#define IB_IP_IOCB_RSP_3032_NUC                0x04
+#define IB_IP_IOCB_RSP_3032_UDP                0x08
+#define IB_IP_IOCB_RSP_3032_TCP                0x10
+#define IB_IP_IOCB_RSP_3032_IPE                0x20
        __le16 reserved;
 #define IB_IP_IOCB_RSP_R        0x01
        __le32 ial_low;
@@ -524,6 +544,21 @@ enum {
        IP_ADDR_INDEX_REG_FUNC_2_SEC = 0x0005,
        IP_ADDR_INDEX_REG_FUNC_3_PRI = 0x0006,
        IP_ADDR_INDEX_REG_FUNC_3_SEC = 0x0007,
+       IP_ADDR_INDEX_REG_6 = 0x0008,
+       IP_ADDR_INDEX_REG_OFFSET_MASK = 0x0030,
+       IP_ADDR_INDEX_REG_E = 0x0040, 
+};
+enum {
+       QL3032_PORT_CONTROL_DS = 0x0001,
+       QL3032_PORT_CONTROL_HH = 0x0002,
+       QL3032_PORT_CONTROL_EIv6 = 0x0004,
+       QL3032_PORT_CONTROL_EIv4 = 0x0008,
+       QL3032_PORT_CONTROL_ET = 0x0010,
+       QL3032_PORT_CONTROL_EF = 0x0020,
+       QL3032_PORT_CONTROL_DRM = 0x0040,
+       QL3032_PORT_CONTROL_RLB = 0x0080,
+       QL3032_PORT_CONTROL_RCB = 0x0100,
+       QL3032_PORT_CONTROL_KIE = 0x0200,
 };
 
 enum {
@@ -657,7 +692,8 @@ struct ql3xxx_port_registers {
        u32 internalRamWDataReg;
        u32 reclaimedBufferAddrRegLow;
        u32 reclaimedBufferAddrRegHigh;
-       u32 reserved[2];
+       u32 tcpConfiguration;
+       u32 functionControl;
        u32 fpgaRevID;
        u32 localRamAddr;
        u32 localRamDataAutoIncr;
@@ -963,6 +999,7 @@ struct eeprom_data {
 
 #define QL3XXX_VENDOR_ID    0x1077
 #define QL3022_DEVICE_ID    0x3022
+#define QL3032_DEVICE_ID    0x3032
 
 /* MTU & Frame Size stuff */
 #define NORMAL_MTU_SIZE                ETH_DATA_LEN
@@ -1038,11 +1075,41 @@ struct ql_rcv_buf_cb {
        int index;
 };
 
+/*
+ * Original IOCB has 3 sg entries:
+ * first points to skb-data area
+ * second points to first frag
+ * third points to next oal.
+ * OAL has 5 entries:
+ * 1 thru 4 point to frags
+ * fifth points to next oal.
+ */ 
+#define MAX_OAL_CNT ((MAX_SKB_FRAGS-1)/4 + 1)
+
+struct oal_entry {
+       u32 dma_lo;
+       u32 dma_hi;
+       u32 len;
+#define OAL_LAST_ENTRY   0x80000000    /* Last valid buffer in list. */
+#define OAL_CONT_ENTRY   0x40000000    /* points to an OAL. (continuation) */
+       u32 reserved;
+};
+
+struct oal {
+       struct oal_entry oal_entry[5];
+};
+
+struct map_list {
+        DECLARE_PCI_UNMAP_ADDR(mapaddr);
+        DECLARE_PCI_UNMAP_LEN(maplen);
+};
+
 struct ql_tx_buf_cb {
        struct sk_buff *skb;
        struct ob_mac_iocb_req *queue_entry ;
-        DECLARE_PCI_UNMAP_ADDR(mapaddr);
-        DECLARE_PCI_UNMAP_LEN(maplen);
+       int seg_count;
+       struct oal *oal;
+       struct map_list map[MAX_SKB_FRAGS+1]; 
 };
 
 /* definitions for type field */
@@ -1189,6 +1256,7 @@ struct ql3_adapter {
        struct delayed_work reset_work;
        struct delayed_work tx_timeout_work;
        u32 max_frame_size;
+       u32 device_id;
 };
 
 #endif                         /* _QLA3XXX_H_ */
index a914fef..0e345cb 100644 (file)
@@ -15,7 +15,7 @@
 
 #define TBD 0
 
-typedef struct _XENA_dev_config {
+struct XENA_dev_config {
 /* Convention: mHAL_XXX is mask, vHAL_XXX is value */
 
 /* General Control-Status Registers */
@@ -300,6 +300,7 @@ typedef struct _XENA_dev_config {
        u64 gpio_control;
 #define GPIO_CTRL_GPIO_0               BIT(8)
        u64 misc_control;
+#define FAULT_BEHAVIOUR                        BIT(0)
 #define EXT_REQ_EN                     BIT(1)
 #define MISC_LINK_STABILITY_PRD(val)   vBIT(val,29,3)
 
@@ -851,9 +852,9 @@ typedef struct _XENA_dev_config {
 #define SPI_CONTROL_DONE               BIT(6)
        u64 spi_data;
 #define SPI_DATA_WRITE(data,len)       vBIT(data,0,len)
-} XENA_dev_config_t;
+};
 
-#define XENA_REG_SPACE sizeof(XENA_dev_config_t)
+#define XENA_REG_SPACE sizeof(struct XENA_dev_config)
 #define        XENA_EEPROM_SPACE (0x01 << 11)
 
 #endif                         /* _REGS_H */
index 1dd66b8..639fbc0 100644 (file)
@@ -77,7 +77,7 @@
 #include "s2io.h"
 #include "s2io-regs.h"
 
-#define DRV_VERSION "2.0.15.2"
+#define DRV_VERSION "2.0.16.1"
 
 /* S2io Driver name & version. */
 static char s2io_driver_name[] = "Neterion";
@@ -86,7 +86,7 @@ static char s2io_driver_version[] = DRV_VERSION;
 static int rxd_size[4] = {32,48,48,64};
 static int rxd_count[4] = {127,85,85,63};
 
-static inline int RXD_IS_UP2DT(RxD_t *rxdp)
+static inline int RXD_IS_UP2DT(struct RxD_t *rxdp)
 {
        int ret;
 
@@ -111,9 +111,9 @@ static inline int RXD_IS_UP2DT(RxD_t *rxdp)
 #define TASKLET_IN_USE test_and_set_bit(0, (&sp->tasklet_status))
 #define PANIC  1
 #define LOW    2
-static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring)
+static inline int rx_buffer_level(struct s2io_nic * sp, int rxb_size, int ring)
 {
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
 
        mac_control = &sp->mac_control;
        if (rxb_size <= rxd_count[sp->rxd_mode])
@@ -286,7 +286,7 @@ static char ethtool_stats_keys[][ETH_GSTRING_LEN] = {
 static void s2io_vlan_rx_register(struct net_device *dev,
                                        struct vlan_group *grp)
 {
-       nic_t *nic = dev->priv;
+       struct s2io_nic *nic = dev->priv;
        unsigned long flags;
 
        spin_lock_irqsave(&nic->tx_lock, flags);
@@ -297,7 +297,7 @@ static void s2io_vlan_rx_register(struct net_device *dev,
 /* Unregister the vlan */
 static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid)
 {
-       nic_t *nic = dev->priv;
+       struct s2io_nic *nic = dev->priv;
        unsigned long flags;
 
        spin_lock_irqsave(&nic->tx_lock, flags);
@@ -401,9 +401,10 @@ S2IO_PARM_INT(lro, 0);
  * aggregation happens until we hit max IP pkt size(64K)
  */
 S2IO_PARM_INT(lro_max_pkts, 0xFFFF);
-#ifndef CONFIG_S2IO_NAPI
 S2IO_PARM_INT(indicate_max_pkts, 0);
-#endif
+
+S2IO_PARM_INT(napi, 1);
+S2IO_PARM_INT(ufo, 0);
 
 static unsigned int tx_fifo_len[MAX_TX_FIFOS] =
     {DEFAULT_FIFO_0_LEN, [1 ...(MAX_TX_FIFOS - 1)] = DEFAULT_FIFO_1_7_LEN};
@@ -457,14 +458,14 @@ static int init_shared_mem(struct s2io_nic *nic)
        u32 size;
        void *tmp_v_addr, *tmp_v_addr_next;
        dma_addr_t tmp_p_addr, tmp_p_addr_next;
-       RxD_block_t *pre_rxd_blk = NULL;
-       int i, j, blk_cnt, rx_sz, tx_sz;
+       struct RxD_block *pre_rxd_blk = NULL;
+       int i, j, blk_cnt;
        int lst_size, lst_per_page;
        struct net_device *dev = nic->dev;
        unsigned long tmp;
-       buffAdd_t *ba;
+       struct buffAdd *ba;
 
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
 
        mac_control = &nic->mac_control;
@@ -482,13 +483,12 @@ static int init_shared_mem(struct s2io_nic *nic)
                return -EINVAL;
        }
 
-       lst_size = (sizeof(TxD_t) * config->max_txds);
-       tx_sz = lst_size * size;
+       lst_size = (sizeof(struct TxD) * config->max_txds);
        lst_per_page = PAGE_SIZE / lst_size;
 
        for (i = 0; i < config->tx_fifo_num; i++) {
                int fifo_len = config->tx_cfg[i].fifo_len;
-               int list_holder_size = fifo_len * sizeof(list_info_hold_t);
+               int list_holder_size = fifo_len * sizeof(struct list_info_hold);
                mac_control->fifos[i].list_info = kmalloc(list_holder_size,
                                                          GFP_KERNEL);
                if (!mac_control->fifos[i].list_info) {
@@ -579,10 +579,9 @@ static int init_shared_mem(struct s2io_nic *nic)
                        mac_control->rings[i].block_count;
        }
        if (nic->rxd_mode == RXD_MODE_1)
-               size = (size * (sizeof(RxD1_t)));
+               size = (size * (sizeof(struct RxD1)));
        else
-               size = (size * (sizeof(RxD3_t)));
-       rx_sz = size;
+               size = (size * (sizeof(struct RxD3)));
 
        for (i = 0; i < config->rx_ring_num; i++) {
                mac_control->rings[i].rx_curr_get_info.block_index = 0;
@@ -600,7 +599,7 @@ static int init_shared_mem(struct s2io_nic *nic)
                                (rxd_count[nic->rxd_mode] + 1);
                /*  Allocating all the Rx blocks */
                for (j = 0; j < blk_cnt; j++) {
-                       rx_block_info_t *rx_blocks;
+                       struct rx_block_info *rx_blocks;
                        int l;
 
                        rx_blocks = &mac_control->rings[i].rx_blocks[j];
@@ -620,9 +619,11 @@ static int init_shared_mem(struct s2io_nic *nic)
                        memset(tmp_v_addr, 0, size);
                        rx_blocks->block_virt_addr = tmp_v_addr;
                        rx_blocks->block_dma_addr = tmp_p_addr;
-                       rx_blocks->rxds = kmalloc(sizeof(rxd_info_t)*
+                       rx_blocks->rxds = kmalloc(sizeof(struct rxd_info)*
                                                  rxd_count[nic->rxd_mode],
                                                  GFP_KERNEL);
+                       if (!rx_blocks->rxds)
+                               return -ENOMEM;
                        for (l=0; l<rxd_count[nic->rxd_mode];l++) {
                                rx_blocks->rxds[l].virt_addr =
                                        rx_blocks->block_virt_addr +
@@ -645,7 +646,7 @@ static int init_shared_mem(struct s2io_nic *nic)
                                mac_control->rings[i].rx_blocks[(j + 1) %
                                              blk_cnt].block_dma_addr;
 
-                       pre_rxd_blk = (RxD_block_t *) tmp_v_addr;
+                       pre_rxd_blk = (struct RxD_block *) tmp_v_addr;
                        pre_rxd_blk->reserved_2_pNext_RxD_block =
                            (unsigned long) tmp_v_addr_next;
                        pre_rxd_blk->pNext_RxD_Blk_physical =
@@ -661,14 +662,14 @@ static int init_shared_mem(struct s2io_nic *nic)
                        blk_cnt = config->rx_cfg[i].num_rxd /
                           (rxd_count[nic->rxd_mode]+ 1);
                        mac_control->rings[i].ba =
-                               kmalloc((sizeof(buffAdd_t *) * blk_cnt),
+                               kmalloc((sizeof(struct buffAdd *) * blk_cnt),
                                     GFP_KERNEL);
                        if (!mac_control->rings[i].ba)
                                return -ENOMEM;
                        for (j = 0; j < blk_cnt; j++) {
                                int k = 0;
                                mac_control->rings[i].ba[j] =
-                                       kmalloc((sizeof(buffAdd_t) *
+                                       kmalloc((sizeof(struct buffAdd) *
                                                (rxd_count[nic->rxd_mode] + 1)),
                                                GFP_KERNEL);
                                if (!mac_control->rings[i].ba[j])
@@ -700,7 +701,7 @@ static int init_shared_mem(struct s2io_nic *nic)
        }
 
        /* Allocation and initialization of Statistics block */
-       size = sizeof(StatInfo_t);
+       size = sizeof(struct stat_block);
        mac_control->stats_mem = pci_alloc_consistent
            (nic->pdev, size, &mac_control->stats_mem_phy);
 
@@ -715,7 +716,7 @@ static int init_shared_mem(struct s2io_nic *nic)
        mac_control->stats_mem_sz = size;
 
        tmp_v_addr = mac_control->stats_mem;
-       mac_control->stats_info = (StatInfo_t *) tmp_v_addr;
+       mac_control->stats_info = (struct stat_block *) tmp_v_addr;
        memset(tmp_v_addr, 0, size);
        DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name,
                  (unsigned long long) tmp_p_addr);
@@ -735,7 +736,7 @@ static void free_shared_mem(struct s2io_nic *nic)
        int i, j, blk_cnt, size;
        void *tmp_v_addr;
        dma_addr_t tmp_p_addr;
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
        int lst_size, lst_per_page;
        struct net_device *dev = nic->dev;
@@ -746,7 +747,7 @@ static void free_shared_mem(struct s2io_nic *nic)
        mac_control = &nic->mac_control;
        config = &nic->config;
 
-       lst_size = (sizeof(TxD_t) * config->max_txds);
+       lst_size = (sizeof(struct TxD) * config->max_txds);
        lst_per_page = PAGE_SIZE / lst_size;
 
        for (i = 0; i < config->tx_fifo_num; i++) {
@@ -809,7 +810,7 @@ static void free_shared_mem(struct s2io_nic *nic)
                                if (!mac_control->rings[i].ba[j])
                                        continue;
                                while (k != rxd_count[nic->rxd_mode]) {
-                                       buffAdd_t *ba =
+                                       struct buffAdd *ba =
                                                &mac_control->rings[i].ba[j][k];
                                        kfree(ba->ba_0_org);
                                        kfree(ba->ba_1_org);
@@ -835,9 +836,9 @@ static void free_shared_mem(struct s2io_nic *nic)
  * s2io_verify_pci_mode -
  */
 
-static int s2io_verify_pci_mode(nic_t *nic)
+static int s2io_verify_pci_mode(struct s2io_nic *nic)
 {
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        register u64 val64 = 0;
        int     mode;
 
@@ -868,9 +869,9 @@ static int bus_speed[8] = {33, 133, 133, 200, 266, 133, 200, 266};
 /**
  * s2io_print_pci_mode -
  */
-static int s2io_print_pci_mode(nic_t *nic)
+static int s2io_print_pci_mode(struct s2io_nic *nic)
 {
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        register u64 val64 = 0;
        int     mode;
        struct config_param *config = &nic->config;
@@ -938,13 +939,13 @@ static int s2io_print_pci_mode(nic_t *nic)
 
 static int init_nic(struct s2io_nic *nic)
 {
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        struct net_device *dev = nic->dev;
        register u64 val64 = 0;
        void __iomem *add;
        u32 time;
        int i, j;
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
        int dtx_cnt = 0;
        unsigned long long mem_share;
@@ -1414,7 +1415,7 @@ static int init_nic(struct s2io_nic *nic)
 
        val64 = TTI_DATA2_MEM_TX_UFC_A(0x10) |
            TTI_DATA2_MEM_TX_UFC_B(0x20) |
-           TTI_DATA2_MEM_TX_UFC_C(0x70) | TTI_DATA2_MEM_TX_UFC_D(0x80);
+           TTI_DATA2_MEM_TX_UFC_C(0x40) | TTI_DATA2_MEM_TX_UFC_D(0x80);
        writeq(val64, &bar0->tti_data2_mem);
 
        val64 = TTI_CMD_MEM_WE | TTI_CMD_MEM_STROBE_NEW_CMD;
@@ -1610,7 +1611,8 @@ static int init_nic(struct s2io_nic *nic)
         * that does not start on an ADB to reduce disconnects.
         */
        if (nic->device_type == XFRAME_II_DEVICE) {
-               val64 = EXT_REQ_EN | MISC_LINK_STABILITY_PRD(3);
+               val64 = FAULT_BEHAVIOUR | EXT_REQ_EN |
+                       MISC_LINK_STABILITY_PRD(3);
                writeq(val64, &bar0->misc_control);
                val64 = readq(&bar0->pic_control2);
                val64 &= ~(BIT(13)|BIT(14)|BIT(15));
@@ -1626,7 +1628,7 @@ static int init_nic(struct s2io_nic *nic)
 #define LINK_UP_DOWN_INTERRUPT         1
 #define MAC_RMAC_ERR_TIMER             2
 
-static int s2io_link_fault_indication(nic_t *nic)
+static int s2io_link_fault_indication(struct s2io_nic *nic)
 {
        if (nic->intr_type != INTA)
                return MAC_RMAC_ERR_TIMER;
@@ -1649,14 +1651,14 @@ static int s2io_link_fault_indication(nic_t *nic)
 
 static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
 {
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        register u64 val64 = 0, temp64 = 0;
 
        /*  Top level interrupt classification */
        /*  PIC Interrupts */
        if ((mask & (TX_PIC_INTR | RX_PIC_INTR))) {
                /*  Enable PIC Intrs in the general intr mask register */
-               val64 = TXPIC_INT_M | PIC_RX_INT_M;
+               val64 = TXPIC_INT_M;
                if (flag == ENABLE_INTRS) {
                        temp64 = readq(&bar0->general_int_mask);
                        temp64 &= ~((u64) val64);
@@ -1694,70 +1696,6 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
                }
        }
 
-       /*  DMA Interrupts */
-       /*  Enabling/Disabling Tx DMA interrupts */
-       if (mask & TX_DMA_INTR) {
-               /* Enable TxDMA Intrs in the general intr mask register */
-               val64 = TXDMA_INT_M;
-               if (flag == ENABLE_INTRS) {
-                       temp64 = readq(&bar0->general_int_mask);
-                       temp64 &= ~((u64) val64);
-                       writeq(temp64, &bar0->general_int_mask);
-                       /*
-                        * Keep all interrupts other than PFC interrupt
-                        * and PCC interrupt disabled in DMA level.
-                        */
-                       val64 = DISABLE_ALL_INTRS & ~(TXDMA_PFC_INT_M |
-                                                     TXDMA_PCC_INT_M);
-                       writeq(val64, &bar0->txdma_int_mask);
-                       /*
-                        * Enable only the MISC error 1 interrupt in PFC block
-                        */
-                       val64 = DISABLE_ALL_INTRS & (~PFC_MISC_ERR_1);
-                       writeq(val64, &bar0->pfc_err_mask);
-                       /*
-                        * Enable only the FB_ECC error interrupt in PCC block
-                        */
-                       val64 = DISABLE_ALL_INTRS & (~PCC_FB_ECC_ERR);
-                       writeq(val64, &bar0->pcc_err_mask);
-               } else if (flag == DISABLE_INTRS) {
-                       /*
-                        * Disable TxDMA Intrs in the general intr mask
-                        * register
-                        */
-                       writeq(DISABLE_ALL_INTRS, &bar0->txdma_int_mask);
-                       writeq(DISABLE_ALL_INTRS, &bar0->pfc_err_mask);
-                       temp64 = readq(&bar0->general_int_mask);
-                       val64 |= temp64;
-                       writeq(val64, &bar0->general_int_mask);
-               }
-       }
-
-       /*  Enabling/Disabling Rx DMA interrupts */
-       if (mask & RX_DMA_INTR) {
-               /*  Enable RxDMA Intrs in the general intr mask register */
-               val64 = RXDMA_INT_M;
-               if (flag == ENABLE_INTRS) {
-                       temp64 = readq(&bar0->general_int_mask);
-                       temp64 &= ~((u64) val64);
-                       writeq(temp64, &bar0->general_int_mask);
-                       /*
-                        * All RxDMA block interrupts are disabled for now
-                        * TODO
-                        */
-                       writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
-               } else if (flag == DISABLE_INTRS) {
-                       /*
-                        * Disable RxDMA Intrs in the general intr mask
-                        * register
-                        */
-                       writeq(DISABLE_ALL_INTRS, &bar0->rxdma_int_mask);
-                       temp64 = readq(&bar0->general_int_mask);
-                       val64 |= temp64;
-                       writeq(val64, &bar0->general_int_mask);
-               }
-       }
-
        /*  MAC Interrupts */
        /*  Enabling/Disabling MAC interrupts */
        if (mask & (TX_MAC_INTR | RX_MAC_INTR)) {
@@ -1784,53 +1722,6 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
                }
        }
 
-       /*  XGXS Interrupts */
-       if (mask & (TX_XGXS_INTR | RX_XGXS_INTR)) {
-               val64 = TXXGXS_INT_M | RXXGXS_INT_M;
-               if (flag == ENABLE_INTRS) {
-                       temp64 = readq(&bar0->general_int_mask);
-                       temp64 &= ~((u64) val64);
-                       writeq(temp64, &bar0->general_int_mask);
-                       /*
-                        * All XGXS block error interrupts are disabled for now
-                        * TODO
-                        */
-                       writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
-               } else if (flag == DISABLE_INTRS) {
-                       /*
-                        * Disable MC Intrs in the general intr mask register
-                        */
-                       writeq(DISABLE_ALL_INTRS, &bar0->xgxs_int_mask);
-                       temp64 = readq(&bar0->general_int_mask);
-                       val64 |= temp64;
-                       writeq(val64, &bar0->general_int_mask);
-               }
-       }
-
-       /*  Memory Controller(MC) interrupts */
-       if (mask & MC_INTR) {
-               val64 = MC_INT_M;
-               if (flag == ENABLE_INTRS) {
-                       temp64 = readq(&bar0->general_int_mask);
-                       temp64 &= ~((u64) val64);
-                       writeq(temp64, &bar0->general_int_mask);
-                       /*
-                        * Enable all MC Intrs.
-                        */
-                       writeq(0x0, &bar0->mc_int_mask);
-                       writeq(0x0, &bar0->mc_err_mask);
-               } else if (flag == DISABLE_INTRS) {
-                       /*
-                        * Disable MC Intrs in the general intr mask register
-                        */
-                       writeq(DISABLE_ALL_INTRS, &bar0->mc_int_mask);
-                       temp64 = readq(&bar0->general_int_mask);
-                       val64 |= temp64;
-                       writeq(val64, &bar0->general_int_mask);
-               }
-       }
-
-
        /*  Tx traffic interrupts */
        if (mask & TX_TRAFFIC_INTR) {
                val64 = TXTRAFFIC_INT_M;
@@ -1877,41 +1768,36 @@ static void en_dis_able_nic_intrs(struct s2io_nic *nic, u16 mask, int flag)
        }
 }
 
-static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
+/**
+ *  verify_pcc_quiescent- Checks for PCC quiescent state
+ *  Return: 1 If PCC is quiescence
+ *          0 If PCC is not quiescence
+ */
+static int verify_pcc_quiescent(struct s2io_nic *sp, int flag)
 {
-       int ret = 0;
+       int ret = 0, herc;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
+       u64 val64 = readq(&bar0->adapter_status);
+       
+       herc = (sp->device_type == XFRAME_II_DEVICE);
 
        if (flag == FALSE) {
-               if ((!herc && (rev_id >= 4)) || herc) {
-                       if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) &&
-                           ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
-                            ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+               if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
+                       if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE))
                                ret = 1;
-                       }
-               }else {
-                       if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
-                           ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
-                            ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+               } else {
+                       if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
                                ret = 1;
-                       }
                }
        } else {
-               if ((!herc && (rev_id >= 4)) || herc) {
+               if ((!herc && (get_xena_rev_id(sp->pdev) >= 4)) || herc) {
                        if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
-                            ADAPTER_STATUS_RMAC_PCC_IDLE) &&
-                           (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
-                            ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
-                             ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
+                            ADAPTER_STATUS_RMAC_PCC_IDLE))
                                ret = 1;
-                       }
                } else {
                        if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
-                            ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) &&
-                           (!(val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ||
-                            ((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
-                             ADAPTER_STATUS_RC_PRC_QUIESCENT))) {
+                            ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
                                ret = 1;
-                       }
                }
        }
 
@@ -1919,9 +1805,6 @@ static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
 }
 /**
  *  verify_xena_quiescence - Checks whether the H/W is ready
- *  @val64 :  Value read from adapter status register.
- *  @flag : indicates if the adapter enable bit was ever written once
- *  before.
  *  Description: Returns whether the H/W is ready to go or not. Depending
  *  on whether adapter enable bit was written or not the comparison
  *  differs and the calling function passes the input argument flag to
@@ -1930,24 +1813,63 @@ static int check_prc_pcc_state(u64 val64, int flag, int rev_id, int herc)
  *          0 If Xena is not quiescence
  */
 
-static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
+static int verify_xena_quiescence(struct s2io_nic *sp)
 {
-       int ret = 0, herc;
-       u64 tmp64 = ~((u64) val64);
-       int rev_id = get_xena_rev_id(sp->pdev);
+       int  mode;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
+       u64 val64 = readq(&bar0->adapter_status);
+       mode = s2io_verify_pci_mode(sp);
 
-       herc = (sp->device_type == XFRAME_II_DEVICE);
-       if (!
-           (tmp64 &
-            (ADAPTER_STATUS_TDMA_READY | ADAPTER_STATUS_RDMA_READY |
-             ADAPTER_STATUS_PFC_READY | ADAPTER_STATUS_TMAC_BUF_EMPTY |
-             ADAPTER_STATUS_PIC_QUIESCENT | ADAPTER_STATUS_MC_DRAM_READY |
-             ADAPTER_STATUS_MC_QUEUES_READY | ADAPTER_STATUS_M_PLL_LOCK |
-             ADAPTER_STATUS_P_PLL_LOCK))) {
-               ret = check_prc_pcc_state(val64, flag, rev_id, herc);
+       if (!(val64 & ADAPTER_STATUS_TDMA_READY)) {
+               DBG_PRINT(ERR_DBG, "%s", "TDMA is not ready!");
+               return 0;
+       }
+       if (!(val64 & ADAPTER_STATUS_RDMA_READY)) {
+       DBG_PRINT(ERR_DBG, "%s", "RDMA is not ready!");
+               return 0;
+       }
+       if (!(val64 & ADAPTER_STATUS_PFC_READY)) {
+               DBG_PRINT(ERR_DBG, "%s", "PFC is not ready!");
+               return 0;
+       }
+       if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) {
+               DBG_PRINT(ERR_DBG, "%s", "TMAC BUF is not empty!");
+               return 0;
+       }
+       if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) {
+               DBG_PRINT(ERR_DBG, "%s", "PIC is not QUIESCENT!");
+               return 0;
+       }
+       if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) {
+               DBG_PRINT(ERR_DBG, "%s", "MC_DRAM is not ready!");
+               return 0;
+       }
+       if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) {
+               DBG_PRINT(ERR_DBG, "%s", "MC_QUEUES is not ready!");
+               return 0;
+       }
+       if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) {
+               DBG_PRINT(ERR_DBG, "%s", "M_PLL is not locked!");
+               return 0;
        }
 
-       return ret;
+       /*
+        * In PCI 33 mode, the P_PLL is not used, and therefore,
+        * the the P_PLL_LOCK bit in the adapter_status register will
+        * not be asserted.
+        */
+       if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) &&
+               sp->device_type == XFRAME_II_DEVICE && mode !=
+               PCI_MODE_PCI_33) {
+               DBG_PRINT(ERR_DBG, "%s", "P_PLL is not locked!");
+               return 0;
+       }
+       if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
+                       ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
+               DBG_PRINT(ERR_DBG, "%s", "RC_PRC is not QUIESCENT!");
+               return 0;
+       }
+       return 1;
 }
 
 /**
@@ -1958,9 +1880,9 @@ static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag)
  *
  */
 
-static void fix_mac_address(nic_t * sp)
+static void fix_mac_address(struct s2io_nic * sp)
 {
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        u64 val64;
        int i = 0;
 
@@ -1986,11 +1908,11 @@ static void fix_mac_address(nic_t * sp)
 
 static int start_nic(struct s2io_nic *nic)
 {
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        struct net_device *dev = nic->dev;
        register u64 val64 = 0;
        u16 subid, i;
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
 
        mac_control = &nic->mac_control;
@@ -2052,7 +1974,7 @@ static int start_nic(struct s2io_nic *nic)
         * it.
         */
        val64 = readq(&bar0->adapter_status);
-       if (!verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
+       if (!verify_xena_quiescence(nic)) {
                DBG_PRINT(ERR_DBG, "%s: device is not ready, ", dev->name);
                DBG_PRINT(ERR_DBG, "Adapter status reads: 0x%llx\n",
                          (unsigned long long) val64);
@@ -2095,11 +2017,12 @@ static int start_nic(struct s2io_nic *nic)
 /**
  * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb
  */
-static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, int get_off)
+static struct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct \
+                                       TxD *txdlp, int get_off)
 {
-       nic_t *nic = fifo_data->nic;
+       struct s2io_nic *nic = fifo_data->nic;
        struct sk_buff *skb;
-       TxD_t *txds;
+       struct TxD *txds;
        u16 j, frg_cnt;
 
        txds = txdlp;
@@ -2113,7 +2036,7 @@ static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, in
        skb = (struct sk_buff *) ((unsigned long)
                        txds->Host_Control);
        if (!skb) {
-               memset(txdlp, 0, (sizeof(TxD_t) * fifo_data->max_txds));
+               memset(txdlp, 0, (sizeof(struct TxD) * fifo_data->max_txds));
                return NULL;
        }
        pci_unmap_single(nic->pdev, (dma_addr_t)
@@ -2132,7 +2055,7 @@ static struct sk_buff *s2io_txdl_getskb(fifo_info_t *fifo_data, TxD_t *txdlp, in
                                       frag->size, PCI_DMA_TODEVICE);
                }
        }
-       memset(txdlp,0, (sizeof(TxD_t) * fifo_data->max_txds));
+       memset(txdlp,0, (sizeof(struct TxD) * fifo_data->max_txds));
        return(skb);
 }
 
@@ -2148,9 +2071,9 @@ static void free_tx_buffers(struct s2io_nic *nic)
 {
        struct net_device *dev = nic->dev;
        struct sk_buff *skb;
-       TxD_t *txdp;
+       struct TxD *txdp;
        int i, j;
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
        int cnt = 0;
 
@@ -2159,7 +2082,7 @@ static void free_tx_buffers(struct s2io_nic *nic)
 
        for (i = 0; i < config->tx_fifo_num; i++) {
                for (j = 0; j < config->tx_cfg[i].fifo_len - 1; j++) {
-                       txdp = (TxD_t *) mac_control->fifos[i].list_info[j].
+                       txdp = (struct TxD *) mac_control->fifos[i].list_info[j].
                            list_virt_addr;
                        skb = s2io_txdl_getskb(&mac_control->fifos[i], txdp, j);
                        if (skb) {
@@ -2187,10 +2110,10 @@ static void free_tx_buffers(struct s2io_nic *nic)
 
 static void stop_nic(struct s2io_nic *nic)
 {
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        register u64 val64 = 0;
        u16 interruptible;
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
 
        mac_control = &nic->mac_control;
@@ -2208,14 +2131,15 @@ static void stop_nic(struct s2io_nic *nic)
        writeq(val64, &bar0->adapter_control);
 }
 
-static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
+static int fill_rxd_3buf(struct s2io_nic *nic, struct RxD_t *rxdp, struct \
+                               sk_buff *skb)
 {
        struct net_device *dev = nic->dev;
        struct sk_buff *frag_list;
        void *tmp;
 
        /* Buffer-1 receives L3/L4 headers */
-       ((RxD3_t*)rxdp)->Buffer1_ptr = pci_map_single
+       ((struct RxD3*)rxdp)->Buffer1_ptr = pci_map_single
                        (nic->pdev, skb->data, l3l4hdr_size + 4,
                        PCI_DMA_FROMDEVICE);
 
@@ -2226,13 +2150,14 @@ static int fill_rxd_3buf(nic_t *nic, RxD_t *rxdp, struct sk_buff *skb)
                return -ENOMEM ;
        }
        frag_list = skb_shinfo(skb)->frag_list;
+       skb->truesize += frag_list->truesize;
        frag_list->next = NULL;
        tmp = (void *)ALIGN((long)frag_list->data, ALIGN_SIZE + 1);
        frag_list->data = tmp;
        frag_list->tail = tmp;
 
        /* Buffer-2 receives L4 data payload */
-       ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
+       ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single(nic->pdev,
                                frag_list->data, dev->mtu,
                                PCI_DMA_FROMDEVICE);
        rxdp->Control_2 |= SET_BUFFER1_SIZE_3(l3l4hdr_size + 4);
@@ -2266,18 +2191,16 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
 {
        struct net_device *dev = nic->dev;
        struct sk_buff *skb;
-       RxD_t *rxdp;
+       struct RxD_t *rxdp;
        int off, off1, size, block_no, block_no1;
        u32 alloc_tab = 0;
        u32 alloc_cnt;
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
        u64 tmp;
-       buffAdd_t *ba;
-#ifndef CONFIG_S2IO_NAPI
+       struct buffAdd *ba;
        unsigned long flags;
-#endif
-       RxD_t *first_rxdp = NULL;
+       struct RxD_t *first_rxdp = NULL;
 
        mac_control = &nic->mac_control;
        config = &nic->config;
@@ -2320,12 +2243,15 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                        DBG_PRINT(INTR_DBG, "%s: Next block at: %p\n",
                                  dev->name, rxdp);
                }
-#ifndef CONFIG_S2IO_NAPI
-               spin_lock_irqsave(&nic->put_lock, flags);
-               mac_control->rings[ring_no].put_pos =
-                   (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
-               spin_unlock_irqrestore(&nic->put_lock, flags);
-#endif
+               if(!napi) {
+                       spin_lock_irqsave(&nic->put_lock, flags);
+                       mac_control->rings[ring_no].put_pos =
+                       (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
+                       spin_unlock_irqrestore(&nic->put_lock, flags);
+               } else {
+                       mac_control->rings[ring_no].put_pos =
+                       (block_no * (rxd_count[nic->rxd_mode] + 1)) + off;
+               }
                if ((rxdp->Control_1 & RXD_OWN_XENA) &&
                        ((nic->rxd_mode >= RXD_MODE_3A) &&
                                (rxdp->Control_2 & BIT(0)))) {
@@ -2356,9 +2282,9 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                }
                if (nic->rxd_mode == RXD_MODE_1) {
                        /* 1 buffer mode - normal operation mode */
-                       memset(rxdp, 0, sizeof(RxD1_t));
+                       memset(rxdp, 0, sizeof(struct RxD1));
                        skb_reserve(skb, NET_IP_ALIGN);
-                       ((RxD1_t*)rxdp)->Buffer0_ptr = pci_map_single
+                       ((struct RxD1*)rxdp)->Buffer0_ptr = pci_map_single
                            (nic->pdev, skb->data, size - NET_IP_ALIGN,
                                PCI_DMA_FROMDEVICE);
                        rxdp->Control_2 = SET_BUFFER0_SIZE_1(size - NET_IP_ALIGN);
@@ -2375,7 +2301,7 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                         * payload
                         */
 
-                       memset(rxdp, 0, sizeof(RxD3_t));
+                       memset(rxdp, 0, sizeof(struct RxD3));
                        ba = &mac_control->rings[ring_no].ba[block_no][off];
                        skb_reserve(skb, BUF0_LEN);
                        tmp = (u64)(unsigned long) skb->data;
@@ -2384,13 +2310,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                        skb->data = (void *) (unsigned long)tmp;
                        skb->tail = (void *) (unsigned long)tmp;
 
-                       if (!(((RxD3_t*)rxdp)->Buffer0_ptr))
-                               ((RxD3_t*)rxdp)->Buffer0_ptr =
+                       if (!(((struct RxD3*)rxdp)->Buffer0_ptr))
+                               ((struct RxD3*)rxdp)->Buffer0_ptr =
                                   pci_map_single(nic->pdev, ba->ba_0, BUF0_LEN,
                                           PCI_DMA_FROMDEVICE);
                        else
                                pci_dma_sync_single_for_device(nic->pdev,
-                                   (dma_addr_t) ((RxD3_t*)rxdp)->Buffer0_ptr,
+                                   (dma_addr_t) ((struct RxD3*)rxdp)->Buffer0_ptr,
                                    BUF0_LEN, PCI_DMA_FROMDEVICE);
                        rxdp->Control_2 = SET_BUFFER0_SIZE_3(BUF0_LEN);
                        if (nic->rxd_mode == RXD_MODE_3B) {
@@ -2400,13 +2326,13 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
                                 * Buffer2 will have L3/L4 header plus
                                 * L4 payload
                                 */
-                               ((RxD3_t*)rxdp)->Buffer2_ptr = pci_map_single
+                               ((struct RxD3*)rxdp)->Buffer2_ptr = pci_map_single
                                (nic->pdev, skb->data, dev->mtu + 4,
                                                PCI_DMA_FROMDEVICE);
 
                                /* Buffer-1 will be dummy buffer. Not used */
-                               if (!(((RxD3_t*)rxdp)->Buffer1_ptr)) {
-                                       ((RxD3_t*)rxdp)->Buffer1_ptr =
+                               if (!(((struct RxD3*)rxdp)->Buffer1_ptr)) {
+                                       ((struct RxD3*)rxdp)->Buffer1_ptr =
                                                pci_map_single(nic->pdev,
                                                ba->ba_1, BUF1_LEN,
                                                PCI_DMA_FROMDEVICE);
@@ -2466,9 +2392,9 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
        struct net_device *dev = sp->dev;
        int j;
        struct sk_buff *skb;
-       RxD_t *rxdp;
-       mac_info_t *mac_control;
-       buffAdd_t *ba;
+       struct RxD_t *rxdp;
+       struct mac_info *mac_control;
+       struct buffAdd *ba;
 
        mac_control = &sp->mac_control;
        for (j = 0 ; j < rxd_count[sp->rxd_mode]; j++) {
@@ -2481,41 +2407,41 @@ static void free_rxd_blk(struct s2io_nic *sp, int ring_no, int blk)
                }
                if (sp->rxd_mode == RXD_MODE_1) {
                        pci_unmap_single(sp->pdev, (dma_addr_t)
-                                ((RxD1_t*)rxdp)->Buffer0_ptr,
+                                ((struct RxD1*)rxdp)->Buffer0_ptr,
                                 dev->mtu +
                                 HEADER_ETHERNET_II_802_3_SIZE
                                 + HEADER_802_2_SIZE +
                                 HEADER_SNAP_SIZE,
                                 PCI_DMA_FROMDEVICE);
-                       memset(rxdp, 0, sizeof(RxD1_t));
+                       memset(rxdp, 0, sizeof(struct RxD1));
                } else if(sp->rxd_mode == RXD_MODE_3B) {
                        ba = &mac_control->rings[ring_no].
                                ba[blk][j];
                        pci_unmap_single(sp->pdev, (dma_addr_t)
-                                ((RxD3_t*)rxdp)->Buffer0_ptr,
+                                ((struct RxD3*)rxdp)->Buffer0_ptr,
                                 BUF0_LEN,
                                 PCI_DMA_FROMDEVICE);
                        pci_unmap_single(sp->pdev, (dma_addr_t)
-                                ((RxD3_t*)rxdp)->Buffer1_ptr,
+                                ((struct RxD3*)rxdp)->Buffer1_ptr,
                                 BUF1_LEN,
                                 PCI_DMA_FROMDEVICE);
                        pci_unmap_single(sp->pdev, (dma_addr_t)
-                                ((RxD3_t*)rxdp)->Buffer2_ptr,
+                                ((struct RxD3*)rxdp)->Buffer2_ptr,
                                 dev->mtu + 4,
                                 PCI_DMA_FROMDEVICE);
-                       memset(rxdp, 0, sizeof(RxD3_t));
+                       memset(rxdp, 0, sizeof(struct RxD3));
                } else {
                        pci_unmap_single(sp->pdev, (dma_addr_t)
-                               ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
+                               ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
                                PCI_DMA_FROMDEVICE);
                        pci_unmap_single(sp->pdev, (dma_addr_t)
-                               ((RxD3_t*)rxdp)->Buffer1_ptr,
+                               ((struct RxD3*)rxdp)->Buffer1_ptr,
                                l3l4hdr_size + 4,
                                PCI_DMA_FROMDEVICE);
                        pci_unmap_single(sp->pdev, (dma_addr_t)
-                               ((RxD3_t*)rxdp)->Buffer2_ptr, dev->mtu,
+                               ((struct RxD3*)rxdp)->Buffer2_ptr, dev->mtu,
                                PCI_DMA_FROMDEVICE);
-                       memset(rxdp, 0, sizeof(RxD3_t));
+                       memset(rxdp, 0, sizeof(struct RxD3));
                }
                dev_kfree_skb(skb);
                atomic_dec(&sp->rx_bufs_left[ring_no]);
@@ -2535,7 +2461,7 @@ static void free_rx_buffers(struct s2io_nic *sp)
 {
        struct net_device *dev = sp->dev;
        int i, blk = 0, buf_cnt = 0;
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
 
        mac_control = &sp->mac_control;
@@ -2568,15 +2494,13 @@ static void free_rx_buffers(struct s2io_nic *sp)
  * 0 on success and 1 if there are No Rx packets to be processed.
  */
 
-#if defined(CONFIG_S2IO_NAPI)
 static int s2io_poll(struct net_device *dev, int *budget)
 {
-       nic_t *nic = dev->priv;
+       struct s2io_nic *nic = dev->priv;
        int pkt_cnt = 0, org_pkts_to_process;
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
-       u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        int i;
 
        atomic_inc(&nic->isr_cnt);
@@ -2588,8 +2512,8 @@ static int s2io_poll(struct net_device *dev, int *budget)
                nic->pkts_to_process = dev->quota;
        org_pkts_to_process = nic->pkts_to_process;
 
-       writeq(val64, &bar0->rx_traffic_int);
-       val64 = readl(&bar0->rx_traffic_int);
+       writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+       readl(&bar0->rx_traffic_int);
 
        for (i = 0; i < config->rx_ring_num; i++) {
                rx_intr_handler(&mac_control->rings[i]);
@@ -2615,7 +2539,7 @@ static int s2io_poll(struct net_device *dev, int *budget)
        }
        /* Re enable the Rx interrupts. */
        writeq(0x0, &bar0->rx_traffic_mask);
-       val64 = readl(&bar0->rx_traffic_mask);
+       readl(&bar0->rx_traffic_mask);
        atomic_dec(&nic->isr_cnt);
        return 0;
 
@@ -2633,7 +2557,6 @@ no_rx:
        atomic_dec(&nic->isr_cnt);
        return 1;
 }
-#endif
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /**
@@ -2647,10 +2570,10 @@ no_rx:
  */
 static void s2io_netpoll(struct net_device *dev)
 {
-       nic_t *nic = dev->priv;
-       mac_info_t *mac_control;
+       struct s2io_nic *nic = dev->priv;
+       struct mac_info *mac_control;
        struct config_param *config;
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        u64 val64 = 0xFFFFFFFFFFFFFFFFULL;
        int i;
 
@@ -2699,17 +2622,15 @@ static void s2io_netpoll(struct net_device *dev)
  *  Return Value:
  *  NONE.
  */
-static void rx_intr_handler(ring_info_t *ring_data)
+static void rx_intr_handler(struct ring_info *ring_data)
 {
-       nic_t *nic = ring_data->nic;
+       struct s2io_nic *nic = ring_data->nic;
        struct net_device *dev = (struct net_device *) nic->dev;
        int get_block, put_block, put_offset;
-       rx_curr_get_info_t get_info, put_info;
-       RxD_t *rxdp;
+       struct rx_curr_get_info get_info, put_info;
+       struct RxD_t *rxdp;
        struct sk_buff *skb;
-#ifndef CONFIG_S2IO_NAPI
        int pkt_cnt = 0;
-#endif
        int i;
 
        spin_lock(&nic->rx_lock);
@@ -2722,19 +2643,21 @@ static void rx_intr_handler(ring_info_t *ring_data)
 
        get_info = ring_data->rx_curr_get_info;
        get_block = get_info.block_index;
-       put_info = ring_data->rx_curr_put_info;
+       memcpy(&put_info, &ring_data->rx_curr_put_info, sizeof(put_info));
        put_block = put_info.block_index;
        rxdp = ring_data->rx_blocks[get_block].rxds[get_info.offset].virt_addr;
-#ifndef CONFIG_S2IO_NAPI
-       spin_lock(&nic->put_lock);
-       put_offset = ring_data->put_pos;
-       spin_unlock(&nic->put_lock);
-#else
-       put_offset = (put_block * (rxd_count[nic->rxd_mode] + 1)) +
-               put_info.offset;
-#endif
+       if (!napi) {
+               spin_lock(&nic->put_lock);
+               put_offset = ring_data->put_pos;
+               spin_unlock(&nic->put_lock);
+       } else
+               put_offset = ring_data->put_pos;
+
        while (RXD_IS_UP2DT(rxdp)) {
-               /* If your are next to put index then it's FIFO full condition */
+               /*
+                * If your are next to put index then it's
+                * FIFO full condition
+                */
                if ((get_block == put_block) &&
                    (get_info.offset + 1) == put_info.offset) {
                        DBG_PRINT(INTR_DBG, "%s: Ring Full\n",dev->name);
@@ -2750,7 +2673,7 @@ static void rx_intr_handler(ring_info_t *ring_data)
                }
                if (nic->rxd_mode == RXD_MODE_1) {
                        pci_unmap_single(nic->pdev, (dma_addr_t)
-                                ((RxD1_t*)rxdp)->Buffer0_ptr,
+                                ((struct RxD1*)rxdp)->Buffer0_ptr,
                                 dev->mtu +
                                 HEADER_ETHERNET_II_802_3_SIZE +
                                 HEADER_802_2_SIZE +
@@ -2758,22 +2681,22 @@ static void rx_intr_handler(ring_info_t *ring_data)
                                 PCI_DMA_FROMDEVICE);
                } else if (nic->rxd_mode == RXD_MODE_3B) {
                        pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
-                                ((RxD3_t*)rxdp)->Buffer0_ptr,
+                                ((struct RxD3*)rxdp)->Buffer0_ptr,
                                 BUF0_LEN, PCI_DMA_FROMDEVICE);
                        pci_unmap_single(nic->pdev, (dma_addr_t)
-                                ((RxD3_t*)rxdp)->Buffer2_ptr,
+                                ((struct RxD3*)rxdp)->Buffer2_ptr,
                                 dev->mtu + 4,
                                 PCI_DMA_FROMDEVICE);
                } else {
                        pci_dma_sync_single_for_cpu(nic->pdev, (dma_addr_t)
-                                        ((RxD3_t*)rxdp)->Buffer0_ptr, BUF0_LEN,
+                                        ((struct RxD3*)rxdp)->Buffer0_ptr, BUF0_LEN,
                                         PCI_DMA_FROMDEVICE);
                        pci_unmap_single(nic->pdev, (dma_addr_t)
-                                        ((RxD3_t*)rxdp)->Buffer1_ptr,
+                                        ((struct RxD3*)rxdp)->Buffer1_ptr,
                                         l3l4hdr_size + 4,
                                         PCI_DMA_FROMDEVICE);
                        pci_unmap_single(nic->pdev, (dma_addr_t)
-                                        ((RxD3_t*)rxdp)->Buffer2_ptr,
+                                        ((struct RxD3*)rxdp)->Buffer2_ptr,
                                         dev->mtu, PCI_DMA_FROMDEVICE);
                }
                prefetch(skb->data);
@@ -2792,20 +2715,17 @@ static void rx_intr_handler(ring_info_t *ring_data)
                        rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
                }
 
-#ifdef CONFIG_S2IO_NAPI
                nic->pkts_to_process -= 1;
-               if (!nic->pkts_to_process)
+               if ((napi) && (!nic->pkts_to_process))
                        break;
-#else
                pkt_cnt++;
                if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts))
                        break;
-#endif
        }
        if (nic->lro) {
                /* Clear all LRO sessions before exiting */
                for (i=0; i<MAX_LRO_SESSIONS; i++) {
-                       lro_t *lro = &nic->lro0_n[i];
+                       struct lro *lro = &nic->lro0_n[i];
                        if (lro->in_use) {
                                update_L3L4_header(nic, lro);
                                queue_rx_frame(lro->parent);
@@ -2829,17 +2749,17 @@ static void rx_intr_handler(ring_info_t *ring_data)
  *  NONE
  */
 
-static void tx_intr_handler(fifo_info_t *fifo_data)
+static void tx_intr_handler(struct fifo_info *fifo_data)
 {
-       nic_t *nic = fifo_data->nic;
+       struct s2io_nic *nic = fifo_data->nic;
        struct net_device *dev = (struct net_device *) nic->dev;
-       tx_curr_get_info_t get_info, put_info;
+       struct tx_curr_get_info get_info, put_info;
        struct sk_buff *skb;
-       TxD_t *txdlp;
+       struct TxD *txdlp;
 
        get_info = fifo_data->tx_curr_get_info;
-       put_info = fifo_data->tx_curr_put_info;
-       txdlp = (TxD_t *) fifo_data->list_info[get_info.offset].
+       memcpy(&put_info, &fifo_data->tx_curr_put_info, sizeof(put_info));
+       txdlp = (struct TxD *) fifo_data->list_info[get_info.offset].
            list_virt_addr;
        while ((!(txdlp->Control_1 & TXD_LIST_OWN_XENA)) &&
               (get_info.offset != put_info.offset) &&
@@ -2854,11 +2774,10 @@ static void tx_intr_handler(fifo_info_t *fifo_data)
                        }
                        if ((err >> 48) == 0xA) {
                                DBG_PRINT(TX_DBG, "TxD returned due \
-to loss of link\n");
+                                               to loss of link\n");
                        }
                        else {
-                               DBG_PRINT(ERR_DBG, "***TxD error \
-%llx\n", err);
+                               DBG_PRINT(ERR_DBG, "***TxD error %llx\n", err);
                        }
                }
 
@@ -2877,7 +2796,7 @@ to loss of link\n");
                get_info.offset++;
                if (get_info.offset == get_info.fifo_len + 1)
                        get_info.offset = 0;
-               txdlp = (TxD_t *) fifo_data->list_info
+               txdlp = (struct TxD *) fifo_data->list_info
                    [get_info.offset].list_virt_addr;
                fifo_data->tx_curr_get_info.offset =
                    get_info.offset;
@@ -2902,8 +2821,8 @@ to loss of link\n");
 static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
 {
        u64 val64 = 0x0;
-       nic_t *sp = dev->priv;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct s2io_nic *sp = dev->priv;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
        //address transaction
        val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -2951,8 +2870,8 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
 {
        u64 val64 = 0x0;
        u64 rval64 = 0x0;
-       nic_t *sp = dev->priv;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct s2io_nic *sp = dev->priv;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
        /* address transaction */
        val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
@@ -3055,8 +2974,8 @@ static void s2io_updt_xpak_counter(struct net_device *dev)
        u64 val64 = 0x0;
        u64 addr  = 0x0;
 
-       nic_t *sp = dev->priv;
-       StatInfo_t *stat_info = sp->mac_control.stats_info;
+       struct s2io_nic *sp = dev->priv;
+       struct stat_block *stat_info = sp->mac_control.stats_info;
 
        /* Check the communication with the MDIO slave */
        addr = 0x0000;
@@ -3154,10 +3073,12 @@ static void s2io_updt_xpak_counter(struct net_device *dev)
 static void alarm_intr_handler(struct s2io_nic *nic)
 {
        struct net_device *dev = (struct net_device *) nic->dev;
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        register u64 val64 = 0, err_reg = 0;
        u64 cnt;
        int i;
+       if (atomic_read(&nic->card_state) == CARD_DOWN)
+               return;
        nic->mac_control.stats_info->sw_stat.ring_full_cnt = 0;
        /* Handling the XPAK counters update */
        if(nic->mac_control.stats_info->xpak_stat.xpak_timer_count < 72000) {
@@ -3297,6 +3218,25 @@ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
        }
        return ret;
 }
+/*
+ * check_pci_device_id - Checks if the device id is supported
+ * @id : device id
+ * Description: Function to check if the pci device id is supported by driver.
+ * Return value: Actual device id if supported else PCI_ANY_ID
+ */
+static u16 check_pci_device_id(u16 id)
+{
+       switch (id) {
+       case PCI_DEVICE_ID_HERC_WIN:
+       case PCI_DEVICE_ID_HERC_UNI:
+               return XFRAME_II_DEVICE;
+       case PCI_DEVICE_ID_S2IO_UNI:
+       case PCI_DEVICE_ID_S2IO_WIN:
+               return XFRAME_I_DEVICE;
+       default:
+               return PCI_ANY_ID;
+       }
+}
 
 /**
  *  s2io_reset - Resets the card.
@@ -3308,42 +3248,57 @@ static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
  *  void.
  */
 
-static void s2io_reset(nic_t * sp)
+static void s2io_reset(struct s2io_nic * sp)
 {
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        u64 val64;
        u16 subid, pci_cmd;
+       int i;
+       u16 val16;
+       DBG_PRINT(INIT_DBG,"%s - Resetting XFrame card %s\n",
+                       __FUNCTION__, sp->dev->name);
 
        /* Back up  the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
        pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
 
+       if (sp->device_type == XFRAME_II_DEVICE) {
+               int ret;
+               ret = pci_set_power_state(sp->pdev, 3);
+               if (!ret)
+                       ret = pci_set_power_state(sp->pdev, 0);
+               else {
+                       DBG_PRINT(ERR_DBG,"%s PME based SW_Reset failed!\n",
+                                       __FUNCTION__);
+                       goto old_way;
+               }
+               msleep(20);
+               goto new_way;
+       }
+old_way:
        val64 = SW_RESET_ALL;
        writeq(val64, &bar0->sw_reset);
-
-       /*
-        * At this stage, if the PCI write is indeed completed, the
-        * card is reset and so is the PCI Config space of the device.
-        * So a read cannot be issued at this stage on any of the
-        * registers to ensure the write into "sw_reset" register
-        * has gone through.
-        * Question: Is there any system call that will explicitly force
-        * all the write commands still pending on the bus to be pushed
-        * through?
-        * As of now I'am just giving a 250ms delay and hoping that the
-        * PCI write to sw_reset register is done by this time.
-        */
-       msleep(250);
+new_way:
        if (strstr(sp->product_name, "CX4")) {
                msleep(750);
        }
+       msleep(250);
+       for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) {
 
-       /* Restore the PCI state saved during initialization. */
-       pci_restore_state(sp->pdev);
-       pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER,
-                                    pci_cmd);
-       s2io_init_pci(sp);
+               /* Restore the PCI state saved during initialization. */
+               pci_restore_state(sp->pdev);
+               pci_read_config_word(sp->pdev, 0x2, &val16);
+               if (check_pci_device_id(val16) != (u16)PCI_ANY_ID)
+                       break;
+               msleep(200);
+       }
 
-       msleep(250);
+       if (check_pci_device_id(val16) == (u16)PCI_ANY_ID) {
+               DBG_PRINT(ERR_DBG,"%s SW_Reset failed!\n", __FUNCTION__);
+       }
+
+       pci_write_config_word(sp->pdev, PCIX_COMMAND_REGISTER, pci_cmd);
+
+       s2io_init_pci(sp);
 
        /* Set swapper to enable I/O register access */
        s2io_set_swapper(sp);
@@ -3399,10 +3354,10 @@ static void s2io_reset(nic_t * sp)
  *  SUCCESS on success and FAILURE on failure.
  */
 
-static int s2io_set_swapper(nic_t * sp)
+static int s2io_set_swapper(struct s2io_nic * sp)
 {
        struct net_device *dev = sp->dev;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        u64 val64, valt, valr;
 
        /*
@@ -3527,9 +3482,9 @@ static int s2io_set_swapper(nic_t * sp)
        return SUCCESS;
 }
 
-static int wait_for_msix_trans(nic_t *nic, int i)
+static int wait_for_msix_trans(struct s2io_nic *nic, int i)
 {
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        u64 val64;
        int ret = 0, cnt = 0;
 
@@ -3548,9 +3503,9 @@ static int wait_for_msix_trans(nic_t *nic, int i)
        return ret;
 }
 
-static void restore_xmsi_data(nic_t *nic)
+static void restore_xmsi_data(struct s2io_nic *nic)
 {
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        u64 val64;
        int i;
 
@@ -3566,9 +3521,9 @@ static void restore_xmsi_data(nic_t *nic)
        }
 }
 
-static void store_xmsi_data(nic_t *nic)
+static void store_xmsi_data(struct s2io_nic *nic)
 {
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        u64 val64, addr, data;
        int i;
 
@@ -3589,9 +3544,9 @@ static void store_xmsi_data(nic_t *nic)
        }
 }
 
-int s2io_enable_msi(nic_t *nic)
+int s2io_enable_msi(struct s2io_nic *nic)
 {
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        u16 msi_ctrl, msg_val;
        struct config_param *config = &nic->config;
        struct net_device *dev = nic->dev;
@@ -3639,9 +3594,9 @@ int s2io_enable_msi(nic_t *nic)
        return 0;
 }
 
-static int s2io_enable_msi_x(nic_t *nic)
+static int s2io_enable_msi_x(struct s2io_nic *nic)
 {
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        u64 tx_mat, rx_mat;
        u16 msi_control; /* Temp variable */
        int ret, i, j, msix_indx = 1;
@@ -3749,7 +3704,7 @@ static int s2io_enable_msi_x(nic_t *nic)
 
 static int s2io_open(struct net_device *dev)
 {
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
        int err = 0;
 
        /*
@@ -3802,7 +3757,7 @@ hw_init_failed:
 
 static int s2io_close(struct net_device *dev)
 {
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
 
        flush_scheduled_work();
        netif_stop_queue(dev);
@@ -3828,15 +3783,15 @@ static int s2io_close(struct net_device *dev)
 
 static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
        u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off;
        register u64 val64;
-       TxD_t *txdp;
-       TxFIFO_element_t __iomem *tx_fifo;
+       struct TxD *txdp;
+       struct TxFIFO_element __iomem *tx_fifo;
        unsigned long flags;
        u16 vlan_tag = 0;
        int vlan_priority = 0;
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
        int offload_type;
 
@@ -3864,7 +3819,7 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 
        put_off = (u16) mac_control->fifos[queue].tx_curr_put_info.offset;
        get_off = (u16) mac_control->fifos[queue].tx_curr_get_info.offset;
-       txdp = (TxD_t *) mac_control->fifos[queue].list_info[put_off].
+       txdp = (struct TxD *) mac_control->fifos[queue].list_info[put_off].
                list_virt_addr;
 
        queue_len = mac_control->fifos[queue].tx_curr_put_info.fifo_len + 1;
@@ -3887,12 +3842,10 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        offload_type = s2io_offload_type(skb);
-#ifdef NETIF_F_TSO
        if (offload_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)) {
                txdp->Control_1 |= TXD_TCP_LSO_EN;
                txdp->Control_1 |= TXD_TCP_LSO_MSS(s2io_tcp_mss(skb));
        }
-#endif
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
                txdp->Control_2 |=
                    (TXD_TX_CKO_IPV4_EN | TXD_TX_CKO_TCP_EN |
@@ -3993,13 +3946,13 @@ static int s2io_xmit(struct sk_buff *skb, struct net_device *dev)
 static void
 s2io_alarm_handle(unsigned long data)
 {
-       nic_t *sp = (nic_t *)data;
+       struct s2io_nic *sp = (struct s2io_nic *)data;
 
        alarm_intr_handler(sp);
        mod_timer(&sp->alarm_timer, jiffies + HZ / 2);
 }
 
-static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
+static int s2io_chk_rx_buffers(struct s2io_nic *sp, int rng_n)
 {
        int rxb_size, level;
 
@@ -4031,9 +3984,9 @@ static int s2io_chk_rx_buffers(nic_t *sp, int rng_n)
 static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
 {
        struct net_device *dev = (struct net_device *) dev_id;
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
        int i;
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
 
        atomic_inc(&sp->isr_cnt);
@@ -4063,8 +4016,8 @@ static irqreturn_t s2io_msi_handle(int irq, void *dev_id)
 
 static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
 {
-       ring_info_t *ring = (ring_info_t *)dev_id;
-       nic_t *sp = ring->nic;
+       struct ring_info *ring = (struct ring_info *)dev_id;
+       struct s2io_nic *sp = ring->nic;
 
        atomic_inc(&sp->isr_cnt);
 
@@ -4077,17 +4030,17 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id)
 
 static irqreturn_t s2io_msix_fifo_handle(int irq, void *dev_id)
 {
-       fifo_info_t *fifo = (fifo_info_t *)dev_id;
-       nic_t *sp = fifo->nic;
+       struct fifo_info *fifo = (struct fifo_info *)dev_id;
+       struct s2io_nic *sp = fifo->nic;
 
        atomic_inc(&sp->isr_cnt);
        tx_intr_handler(fifo);
        atomic_dec(&sp->isr_cnt);
        return IRQ_HANDLED;
 }
-static void s2io_txpic_intr_handle(nic_t *sp)
+static void s2io_txpic_intr_handle(struct s2io_nic *sp)
 {
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        u64 val64;
 
        val64 = readq(&bar0->pic_int_status);
@@ -4109,39 +4062,33 @@ static void s2io_txpic_intr_handle(nic_t *sp)
                }
                else if (val64 & GPIO_INT_REG_LINK_UP) {
                        val64 = readq(&bar0->adapter_status);
-                       if (verify_xena_quiescence(sp, val64,
-                                                  sp->device_enabled_once)) {
                                /* Enable Adapter */
-                               val64 = readq(&bar0->adapter_control);
-                               val64 |= ADAPTER_CNTL_EN;
-                               writeq(val64, &bar0->adapter_control);
-                               val64 |= ADAPTER_LED_ON;
-                               writeq(val64, &bar0->adapter_control);
-                               if (!sp->device_enabled_once)
-                                       sp->device_enabled_once = 1;
+                       val64 = readq(&bar0->adapter_control);
+                       val64 |= ADAPTER_CNTL_EN;
+                       writeq(val64, &bar0->adapter_control);
+                       val64 |= ADAPTER_LED_ON;
+                       writeq(val64, &bar0->adapter_control);
+                       if (!sp->device_enabled_once)
+                               sp->device_enabled_once = 1;
 
-                               s2io_link(sp, LINK_UP);
-                               /*
-                                * unmask link down interrupt and mask link-up
-                                * intr
-                                */
-                               val64 = readq(&bar0->gpio_int_mask);
-                               val64 &= ~GPIO_INT_MASK_LINK_DOWN;
-                               val64 |= GPIO_INT_MASK_LINK_UP;
-                               writeq(val64, &bar0->gpio_int_mask);
+                       s2io_link(sp, LINK_UP);
+                       /*
+                        * unmask link down interrupt and mask link-up
+                        * intr
+                        */
+                       val64 = readq(&bar0->gpio_int_mask);
+                       val64 &= ~GPIO_INT_MASK_LINK_DOWN;
+                       val64 |= GPIO_INT_MASK_LINK_UP;
+                       writeq(val64, &bar0->gpio_int_mask);
 
-                       }
                }else if (val64 & GPIO_INT_REG_LINK_DOWN) {
                        val64 = readq(&bar0->adapter_status);
-                       if (verify_xena_quiescence(sp, val64,
-                                                  sp->device_enabled_once)) {
-                               s2io_link(sp, LINK_DOWN);
-                               /* Link is down so unmaks link up interrupt */
-                               val64 = readq(&bar0->gpio_int_mask);
-                               val64 &= ~GPIO_INT_MASK_LINK_UP;
-                               val64 |= GPIO_INT_MASK_LINK_DOWN;
-                               writeq(val64, &bar0->gpio_int_mask);
-                       }
+                       s2io_link(sp, LINK_DOWN);
+                       /* Link is down so unmaks link up interrupt */
+                       val64 = readq(&bar0->gpio_int_mask);
+                       val64 &= ~GPIO_INT_MASK_LINK_UP;
+                       val64 |= GPIO_INT_MASK_LINK_DOWN;
+                       writeq(val64, &bar0->gpio_int_mask);
                }
        }
        val64 = readq(&bar0->gpio_int_mask);
@@ -4163,11 +4110,11 @@ static void s2io_txpic_intr_handle(nic_t *sp)
 static irqreturn_t s2io_isr(int irq, void *dev_id)
 {
        struct net_device *dev = (struct net_device *) dev_id;
-       nic_t *sp = dev->priv;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct s2io_nic *sp = dev->priv;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        int i;
-       u64 reason = 0, val64, org_mask;
-       mac_info_t *mac_control;
+       u64 reason = 0;
+       struct mac_info *mac_control;
        struct config_param *config;
 
        atomic_inc(&sp->isr_cnt);
@@ -4185,43 +4132,48 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
        reason = readq(&bar0->general_int_status);
 
        if (!reason) {
-               /* The interrupt was not raised by Xena. */
+               /* The interrupt was not raised by us. */
+               atomic_dec(&sp->isr_cnt);
+               return IRQ_NONE;
+       }
+       else if (unlikely(reason == S2IO_MINUS_ONE) ) {
+               /* Disable device and get out */
                atomic_dec(&sp->isr_cnt);
                return IRQ_NONE;
        }
 
-       val64 = 0xFFFFFFFFFFFFFFFFULL;
-       /* Store current mask before masking all interrupts */
-       org_mask = readq(&bar0->general_int_mask);
-       writeq(val64, &bar0->general_int_mask);
+       if (napi) {
+               if (reason & GEN_INTR_RXTRAFFIC) {
+                       if ( likely ( netif_rx_schedule_prep(dev)) ) {
+                               __netif_rx_schedule(dev);
+                               writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
+                       }
+                       else
+                               writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
+               }
+       } else {
+               /*
+                * Rx handler is called by default, without checking for the
+                * cause of interrupt.
+                * rx_traffic_int reg is an R1 register, writing all 1's
+                * will ensure that the actual interrupt causing bit get's
+                * cleared and hence a read can be avoided.
+                */
+               if (reason & GEN_INTR_RXTRAFFIC)
+                       writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
 
-#ifdef CONFIG_S2IO_NAPI
-       if (reason & GEN_INTR_RXTRAFFIC) {
-               if (netif_rx_schedule_prep(dev)) {
-                       writeq(val64, &bar0->rx_traffic_mask);
-                       __netif_rx_schedule(dev);
+               for (i = 0; i < config->rx_ring_num; i++) {
+                       rx_intr_handler(&mac_control->rings[i]);
                }
        }
-#else
-       /*
-        * Rx handler is called by default, without checking for the
-        * cause of interrupt.
-        * rx_traffic_int reg is an R1 register, writing all 1's
-        * will ensure that the actual interrupt causing bit get's
-        * cleared and hence a read can be avoided.
-        */
-       writeq(val64, &bar0->rx_traffic_int);
-       for (i = 0; i < config->rx_ring_num; i++) {
-               rx_intr_handler(&mac_control->rings[i]);
-       }
-#endif
 
        /*
         * tx_traffic_int reg is an R1 register, writing all 1's
         * will ensure that the actual interrupt causing bit get's
         * cleared and hence a read can be avoided.
         */
-       writeq(val64, &bar0->tx_traffic_int);
+       if (reason & GEN_INTR_TXTRAFFIC)
+               writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
 
        for (i = 0; i < config->tx_fifo_num; i++)
                tx_intr_handler(&mac_control->fifos[i]);
@@ -4233,11 +4185,14 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
         * reallocate the buffers from the interrupt handler itself,
         * else schedule a tasklet to reallocate the buffers.
         */
-#ifndef CONFIG_S2IO_NAPI
-       for (i = 0; i < config->rx_ring_num; i++)
-               s2io_chk_rx_buffers(sp, i);
-#endif
-       writeq(org_mask, &bar0->general_int_mask);
+       if (!napi) {
+               for (i = 0; i < config->rx_ring_num; i++)
+                       s2io_chk_rx_buffers(sp, i);
+       }
+
+       writeq(0, &bar0->general_int_mask);
+       readl(&bar0->general_int_status);
+
        atomic_dec(&sp->isr_cnt);
        return IRQ_HANDLED;
 }
@@ -4245,9 +4200,9 @@ static irqreturn_t s2io_isr(int irq, void *dev_id)
 /**
  * s2io_updt_stats -
  */
-static void s2io_updt_stats(nic_t *sp)
+static void s2io_updt_stats(struct s2io_nic *sp)
 {
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        u64 val64;
        int cnt = 0;
 
@@ -4266,7 +4221,7 @@ static void s2io_updt_stats(nic_t *sp)
                                break; /* Updt failed */
                } while(1);
        } else {
-               memset(sp->mac_control.stats_info, 0, sizeof(StatInfo_t));
+               memset(sp->mac_control.stats_info, 0, sizeof(struct stat_block));
        }
 }
 
@@ -4282,8 +4237,8 @@ static void s2io_updt_stats(nic_t *sp)
 
 static struct net_device_stats *s2io_get_stats(struct net_device *dev)
 {
-       nic_t *sp = dev->priv;
-       mac_info_t *mac_control;
+       struct s2io_nic *sp = dev->priv;
+       struct mac_info *mac_control;
        struct config_param *config;
 
 
@@ -4324,8 +4279,8 @@ static void s2io_set_multicast(struct net_device *dev)
 {
        int i, j, prev_cnt;
        struct dev_mc_list *mclist;
-       nic_t *sp = dev->priv;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct s2io_nic *sp = dev->priv;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
            0xfeffffffffffULL;
        u64 dis_addr = 0xffffffffffffULL, mac_addr = 0;
@@ -4478,8 +4433,8 @@ static void s2io_set_multicast(struct net_device *dev)
 
 static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
 {
-       nic_t *sp = dev->priv;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct s2io_nic *sp = dev->priv;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        register u64 val64, mac_addr = 0;
        int i;
 
@@ -4525,7 +4480,7 @@ static int s2io_set_mac_addr(struct net_device *dev, u8 * addr)
 static int s2io_ethtool_sset(struct net_device *dev,
                             struct ethtool_cmd *info)
 {
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
        if ((info->autoneg == AUTONEG_ENABLE) ||
            (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL))
                return -EINVAL;
@@ -4551,7 +4506,7 @@ static int s2io_ethtool_sset(struct net_device *dev,
 
 static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
 {
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
        info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
        info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE);
        info->port = PORT_FIBRE;
@@ -4584,7 +4539,7 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info)
 static void s2io_ethtool_gdrvinfo(struct net_device *dev,
                                  struct ethtool_drvinfo *info)
 {
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
 
        strncpy(info->driver, s2io_driver_name, sizeof(info->driver));
        strncpy(info->version, s2io_driver_version, sizeof(info->version));
@@ -4616,7 +4571,7 @@ static void s2io_ethtool_gregs(struct net_device *dev,
        int i;
        u64 reg;
        u8 *reg_space = (u8 *) space;
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
 
        regs->len = XENA_REG_SPACE;
        regs->version = sp->pdev->subsystem_device;
@@ -4638,8 +4593,8 @@ static void s2io_ethtool_gregs(struct net_device *dev,
 */
 static void s2io_phy_id(unsigned long data)
 {
-       nic_t *sp = (nic_t *) data;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct s2io_nic *sp = (struct s2io_nic *) data;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        u64 val64 = 0;
        u16 subid;
 
@@ -4676,8 +4631,8 @@ static void s2io_phy_id(unsigned long data)
 static int s2io_ethtool_idnic(struct net_device *dev, u32 data)
 {
        u64 val64 = 0, last_gpio_ctrl_val;
-       nic_t *sp = dev->priv;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct s2io_nic *sp = dev->priv;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        u16 subid;
 
        subid = sp->pdev->subsystem_device;
@@ -4725,8 +4680,8 @@ static void s2io_ethtool_getpause_data(struct net_device *dev,
                                       struct ethtool_pauseparam *ep)
 {
        u64 val64;
-       nic_t *sp = dev->priv;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct s2io_nic *sp = dev->priv;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
        val64 = readq(&bar0->rmac_pause_cfg);
        if (val64 & RMAC_PAUSE_GEN_ENABLE)
@@ -4752,8 +4707,8 @@ static int s2io_ethtool_setpause_data(struct net_device *dev,
                               struct ethtool_pauseparam *ep)
 {
        u64 val64;
-       nic_t *sp = dev->priv;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct s2io_nic *sp = dev->priv;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
        val64 = readq(&bar0->rmac_pause_cfg);
        if (ep->tx_pause)
@@ -4785,12 +4740,12 @@ static int s2io_ethtool_setpause_data(struct net_device *dev,
  */
 
 #define S2IO_DEV_ID            5
-static int read_eeprom(nic_t * sp, int off, u64 * data)
+static int read_eeprom(struct s2io_nic * sp, int off, u64 * data)
 {
        int ret = -1;
        u32 exit_cnt = 0;
        u64 val64;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
        if (sp->device_type == XFRAME_I_DEVICE) {
                val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
@@ -4850,11 +4805,11 @@ static int read_eeprom(nic_t * sp, int off, u64 * data)
  *  0 on success, -1 on failure.
  */
 
-static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
+static int write_eeprom(struct s2io_nic * sp, int off, u64 data, int cnt)
 {
        int exit_cnt = 0, ret = -1;
        u64 val64;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
 
        if (sp->device_type == XFRAME_I_DEVICE) {
                val64 = I2C_CONTROL_DEV_ID(S2IO_DEV_ID) | I2C_CONTROL_ADDR(off) |
@@ -4899,7 +4854,7 @@ static int write_eeprom(nic_t * sp, int off, u64 data, int cnt)
        }
        return ret;
 }
-static void s2io_vpd_read(nic_t *nic)
+static void s2io_vpd_read(struct s2io_nic *nic)
 {
        u8 *vpd_data;
        u8 data;
@@ -4914,6 +4869,7 @@ static void s2io_vpd_read(nic_t *nic)
                strcpy(nic->product_name, "Xframe I 10GbE network adapter");
                vpd_addr = 0x50;
        }
+       strcpy(nic->serial_num, "NOT AVAILABLE");
 
        vpd_data = kmalloc(256, GFP_KERNEL);
        if (!vpd_data)
@@ -4937,7 +4893,22 @@ static void s2io_vpd_read(nic_t *nic)
                pci_read_config_dword(nic->pdev,  (vpd_addr + 4),
                                      (u32 *)&vpd_data[i]);
        }
-       if ((!fail) && (vpd_data[1] < VPD_PRODUCT_NAME_LEN)) {
+
+       if(!fail) {
+               /* read serial number of adapter */
+               for (cnt = 0; cnt < 256; cnt++) {
+               if ((vpd_data[cnt] == 'S') &&
+                       (vpd_data[cnt+1] == 'N') &&
+                       (vpd_data[cnt+2] < VPD_STRING_LEN)) {
+                               memset(nic->serial_num, 0, VPD_STRING_LEN);
+                               memcpy(nic->serial_num, &vpd_data[cnt + 3],
+                                       vpd_data[cnt+2]);
+                               break;
+                       }
+               }
+       }
+
+       if ((!fail) && (vpd_data[1] < VPD_STRING_LEN)) {
                memset(nic->product_name, 0, vpd_data[1]);
                memcpy(nic->product_name, &vpd_data[3], vpd_data[1]);
        }
@@ -4962,7 +4933,7 @@ static int s2io_ethtool_geeprom(struct net_device *dev,
 {
        u32 i, valid;
        u64 data;
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
 
        eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16);
 
@@ -5000,7 +4971,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev,
 {
        int len = eeprom->len, cnt = 0;
        u64 valid = 0, data;
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
 
        if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
                DBG_PRINT(ERR_DBG,
@@ -5044,9 +5015,9 @@ static int s2io_ethtool_seeprom(struct net_device *dev,
  * 0 on success.
  */
 
-static int s2io_register_test(nic_t * sp, uint64_t * data)
+static int s2io_register_test(struct s2io_nic * sp, uint64_t * data)
 {
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        u64 val64 = 0, exp_val;
        int fail = 0;
 
@@ -5111,7 +5082,7 @@ static int s2io_register_test(nic_t * sp, uint64_t * data)
  * 0 on success.
  */
 
-static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
+static int s2io_eeprom_test(struct s2io_nic * sp, uint64_t * data)
 {
        int fail = 0;
        u64 ret_data, org_4F0, org_7F0;
@@ -5213,7 +5184,7 @@ static int s2io_eeprom_test(nic_t * sp, uint64_t * data)
  * 0 on success and -1 on failure.
  */
 
-static int s2io_bist_test(nic_t * sp, uint64_t * data)
+static int s2io_bist_test(struct s2io_nic * sp, uint64_t * data)
 {
        u8 bist = 0;
        int cnt = 0, ret = -1;
@@ -5249,9 +5220,9 @@ static int s2io_bist_test(nic_t * sp, uint64_t * data)
  * 0 on success.
  */
 
-static int s2io_link_test(nic_t * sp, uint64_t * data)
+static int s2io_link_test(struct s2io_nic * sp, uint64_t * data)
 {
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        u64 val64;
 
        val64 = readq(&bar0->adapter_status);
@@ -5276,9 +5247,9 @@ static int s2io_link_test(nic_t * sp, uint64_t * data)
  *  0 on success.
  */
 
-static int s2io_rldram_test(nic_t * sp, uint64_t * data)
+static int s2io_rldram_test(struct s2io_nic * sp, uint64_t * data)
 {
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        u64 val64;
        int cnt, iteration = 0, test_fail = 0;
 
@@ -5380,7 +5351,7 @@ static void s2io_ethtool_test(struct net_device *dev,
                              struct ethtool_test *ethtest,
                              uint64_t * data)
 {
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
        int orig_state = netif_running(sp->dev);
 
        if (ethtest->flags == ETH_TEST_FL_OFFLINE) {
@@ -5436,8 +5407,8 @@ static void s2io_get_ethtool_stats(struct net_device *dev,
                                   u64 * tmp_stats)
 {
        int i = 0;
-       nic_t *sp = dev->priv;
-       StatInfo_t *stat_info = sp->mac_control.stats_info;
+       struct s2io_nic *sp = dev->priv;
+       struct stat_block *stat_info = sp->mac_control.stats_info;
 
        s2io_updt_stats(sp);
        tmp_stats[i++] =
@@ -5664,14 +5635,14 @@ static int s2io_ethtool_get_regs_len(struct net_device *dev)
 
 static u32 s2io_ethtool_get_rx_csum(struct net_device * dev)
 {
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
 
        return (sp->rx_csum);
 }
 
 static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data)
 {
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
 
        if (data)
                sp->rx_csum = 1;
@@ -5750,10 +5721,8 @@ static const struct ethtool_ops netdev_ethtool_ops = {
        .set_tx_csum = s2io_ethtool_op_set_tx_csum,
        .get_sg = ethtool_op_get_sg,
        .set_sg = ethtool_op_set_sg,
-#ifdef NETIF_F_TSO
        .get_tso = s2io_ethtool_op_get_tso,
        .set_tso = s2io_ethtool_op_set_tso,
-#endif
        .get_ufo = ethtool_op_get_ufo,
        .set_ufo = ethtool_op_set_ufo,
        .self_test_count = s2io_ethtool_self_test_count,
@@ -5794,7 +5763,7 @@ static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 
 static int s2io_change_mtu(struct net_device *dev, int new_mtu)
 {
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
 
        if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) {
                DBG_PRINT(ERR_DBG, "%s: MTU size is invalid.\n",
@@ -5813,7 +5782,7 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
                if (netif_queue_stopped(dev))
                        netif_wake_queue(dev);
        } else { /* Device is down */
-               XENA_dev_config_t __iomem *bar0 = sp->bar0;
+               struct XENA_dev_config __iomem *bar0 = sp->bar0;
                u64 val64 = new_mtu;
 
                writeq(vBIT(val64, 2, 14), &bar0->rmac_max_pyld_len);
@@ -5838,9 +5807,9 @@ static int s2io_change_mtu(struct net_device *dev, int new_mtu)
 static void s2io_tasklet(unsigned long dev_addr)
 {
        struct net_device *dev = (struct net_device *) dev_addr;
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
        int i, ret;
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
 
        mac_control = &sp->mac_control;
@@ -5873,9 +5842,9 @@ static void s2io_tasklet(unsigned long dev_addr)
 
 static void s2io_set_link(struct work_struct *work)
 {
-       nic_t *nic = container_of(work, nic_t, set_link_task);
+       struct s2io_nic *nic = container_of(work, struct s2io_nic, set_link_task);
        struct net_device *dev = nic->dev;
-       XENA_dev_config_t __iomem *bar0 = nic->bar0;
+       struct XENA_dev_config __iomem *bar0 = nic->bar0;
        register u64 val64;
        u16 subid;
 
@@ -5894,57 +5863,53 @@ static void s2io_set_link(struct work_struct *work)
        }
 
        val64 = readq(&bar0->adapter_status);
-       if (verify_xena_quiescence(nic, val64, nic->device_enabled_once)) {
-               if (LINK_IS_UP(val64)) {
-                       val64 = readq(&bar0->adapter_control);
-                       val64 |= ADAPTER_CNTL_EN;
-                       writeq(val64, &bar0->adapter_control);
-                       if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
-                                                            subid)) {
-                               val64 = readq(&bar0->gpio_control);
-                               val64 |= GPIO_CTRL_GPIO_0;
-                               writeq(val64, &bar0->gpio_control);
-                               val64 = readq(&bar0->gpio_control);
-                       } else {
-                               val64 |= ADAPTER_LED_ON;
+       if (LINK_IS_UP(val64)) {
+               if (!(readq(&bar0->adapter_control) & ADAPTER_CNTL_EN)) {
+                       if (verify_xena_quiescence(nic)) {
+                               val64 = readq(&bar0->adapter_control);
+                               val64 |= ADAPTER_CNTL_EN;
                                writeq(val64, &bar0->adapter_control);
-                       }
-                       if (s2io_link_fault_indication(nic) ==
-                                               MAC_RMAC_ERR_TIMER) {
-                               val64 = readq(&bar0->adapter_status);
-                               if (!LINK_IS_UP(val64)) {
-                                       DBG_PRINT(ERR_DBG, "%s:", dev->name);
-                                       DBG_PRINT(ERR_DBG, " Link down");
-                                       DBG_PRINT(ERR_DBG, "after ");
-                                       DBG_PRINT(ERR_DBG, "enabling ");
-                                       DBG_PRINT(ERR_DBG, "device \n");
+                               if (CARDS_WITH_FAULTY_LINK_INDICATORS(
+                                       nic->device_type, subid)) {
+                                       val64 = readq(&bar0->gpio_control);
+                                       val64 |= GPIO_CTRL_GPIO_0;
+                                       writeq(val64, &bar0->gpio_control);
+                                       val64 = readq(&bar0->gpio_control);
+                               } else {
+                                       val64 |= ADAPTER_LED_ON;
+                                       writeq(val64, &bar0->adapter_control);
                                }
-                       }
-                       if (nic->device_enabled_once == FALSE) {
                                nic->device_enabled_once = TRUE;
+                       } else {
+                               DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
+                               DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
+                               netif_stop_queue(dev);
                        }
+               }
+               val64 = readq(&bar0->adapter_status);
+               if (!LINK_IS_UP(val64)) {
+                       DBG_PRINT(ERR_DBG, "%s:", dev->name);
+                       DBG_PRINT(ERR_DBG, " Link down after enabling ");
+                       DBG_PRINT(ERR_DBG, "device \n");
+               } else
                        s2io_link(nic, LINK_UP);
-               } else {
-                       if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
-                                                             subid)) {
-                               val64 = readq(&bar0->gpio_control);
-                               val64 &= ~GPIO_CTRL_GPIO_0;
-                               writeq(val64, &bar0->gpio_control);
-                               val64 = readq(&bar0->gpio_control);
-                       }
-                       s2io_link(nic, LINK_DOWN);
+       } else {
+               if (CARDS_WITH_FAULTY_LINK_INDICATORS(nic->device_type,
+                                                     subid)) {
+                       val64 = readq(&bar0->gpio_control);
+                       val64 &= ~GPIO_CTRL_GPIO_0;
+                       writeq(val64, &bar0->gpio_control);
+                       val64 = readq(&bar0->gpio_control);
                }
-       } else {                /* NIC is not Quiescent. */
-               DBG_PRINT(ERR_DBG, "%s: Error: ", dev->name);
-               DBG_PRINT(ERR_DBG, "device is not Quiescent\n");
-               netif_stop_queue(dev);
+               s2io_link(nic, LINK_DOWN);
        }
        clear_bit(0, &(nic->link_state));
 }
 
-static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
-                          struct sk_buff **skb, u64 *temp0, u64 *temp1,
-                          u64 *temp2, int size)
+static int set_rxd_buffer_pointer(struct s2io_nic *sp, struct RxD_t *rxdp,
+                               struct buffAdd *ba,
+                               struct sk_buff **skb, u64 *temp0, u64 *temp1,
+                               u64 *temp2, int size)
 {
        struct net_device *dev = sp->dev;
        struct sk_buff *frag_list;
@@ -5958,7 +5923,7 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
                         * using same mapped address for the Rxd
                         * buffer pointer
                         */
-                       ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0;
+                       ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0;
                } else {
                        *skb = dev_alloc_skb(size);
                        if (!(*skb)) {
@@ -5970,7 +5935,7 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
                         * such it will be used for next rxd whose
                         * Host Control is NULL
                         */
-                       ((RxD1_t*)rxdp)->Buffer0_ptr = *temp0 =
+                       ((struct RxD1*)rxdp)->Buffer0_ptr = *temp0 =
                                pci_map_single( sp->pdev, (*skb)->data,
                                        size - NET_IP_ALIGN,
                                        PCI_DMA_FROMDEVICE);
@@ -5979,36 +5944,36 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
        } else if ((sp->rxd_mode == RXD_MODE_3B) && (rxdp->Host_Control == 0)) {
                /* Two buffer Mode */
                if (*skb) {
-                       ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
-                       ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
-                       ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
+                       ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
+                       ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
+                       ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
                } else {
                        *skb = dev_alloc_skb(size);
                        if (!(*skb)) {
                                DBG_PRINT(ERR_DBG, "%s: dev_alloc_skb failed\n",
-                                         dev->name);
+                                       dev->name);
                                return -ENOMEM;
                        }
-                       ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
+                       ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
                                pci_map_single(sp->pdev, (*skb)->data,
                                               dev->mtu + 4,
                                               PCI_DMA_FROMDEVICE);
-                       ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
+                       ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
                                pci_map_single( sp->pdev, ba->ba_0, BUF0_LEN,
                                                PCI_DMA_FROMDEVICE);
                        rxdp->Host_Control = (unsigned long) (*skb);
 
                        /* Buffer-1 will be dummy buffer not used */
-                       ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
+                       ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
                                pci_map_single(sp->pdev, ba->ba_1, BUF1_LEN,
                                               PCI_DMA_FROMDEVICE);
                }
        } else if ((rxdp->Host_Control == 0)) {
                /* Three buffer mode */
                if (*skb) {
-                       ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0;
-                       ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1;
-                       ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2;
+                       ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0;
+                       ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1;
+                       ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2;
                } else {
                        *skb = dev_alloc_skb(size);
                        if (!(*skb)) {
@@ -6016,11 +5981,11 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
                                          dev->name);
                                return -ENOMEM;
                        }
-                       ((RxD3_t*)rxdp)->Buffer0_ptr = *temp0 =
+                       ((struct RxD3*)rxdp)->Buffer0_ptr = *temp0 =
                                pci_map_single(sp->pdev, ba->ba_0, BUF0_LEN,
                                               PCI_DMA_FROMDEVICE);
                        /* Buffer-1 receives L3/L4 headers */
-                       ((RxD3_t*)rxdp)->Buffer1_ptr = *temp1 =
+                       ((struct RxD3*)rxdp)->Buffer1_ptr = *temp1 =
                                pci_map_single( sp->pdev, (*skb)->data,
                                                l3l4hdr_size + 4,
                                                PCI_DMA_FROMDEVICE);
@@ -6040,14 +6005,15 @@ static int set_rxd_buffer_pointer(nic_t *sp, RxD_t *rxdp, buffAdd_t *ba,
                        /*
                         * Buffer-2 receives L4 data payload
                         */
-                       ((RxD3_t*)rxdp)->Buffer2_ptr = *temp2 =
+                       ((struct RxD3*)rxdp)->Buffer2_ptr = *temp2 =
                                pci_map_single( sp->pdev, frag_list->data,
                                                dev->mtu, PCI_DMA_FROMDEVICE);
                }
        }
        return 0;
 }
-static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size)
+static void set_rxd_buffer_size(struct s2io_nic *sp, struct RxD_t *rxdp,
+                               int size)
 {
        struct net_device *dev = sp->dev;
        if (sp->rxd_mode == RXD_MODE_1) {
@@ -6063,15 +6029,15 @@ static void set_rxd_buffer_size(nic_t *sp, RxD_t *rxdp, int size)
        }
 }
 
-static  int rxd_owner_bit_reset(nic_t *sp)
+static  int rxd_owner_bit_reset(struct s2io_nic *sp)
 {
        int i, j, k, blk_cnt = 0, size;
-       mac_info_t * mac_control = &sp->mac_control;
+       struct mac_info * mac_control = &sp->mac_control;
        struct config_param *config = &sp->config;
        struct net_device *dev = sp->dev;
-       RxD_t *rxdp = NULL;
+       struct RxD_t *rxdp = NULL;
        struct sk_buff *skb = NULL;
-       buffAdd_t *ba = NULL;
+       struct buffAdd *ba = NULL;
        u64 temp0_64 = 0, temp1_64 = 0, temp2_64 = 0;
 
        /* Calculate the size based on ring mode */
@@ -6110,7 +6076,7 @@ static  int rxd_owner_bit_reset(nic_t *sp)
 
 }
 
-static int s2io_add_isr(nic_t * sp)
+static int s2io_add_isr(struct s2io_nic * sp)
 {
        int ret = 0;
        struct net_device *dev = sp->dev;
@@ -6125,7 +6091,7 @@ static int s2io_add_isr(nic_t * sp)
                sp->intr_type = INTA;
        }
 
-       /* Store the values of the MSIX table in the nic_t structure */
+       /* Store the values of the MSIX table in the struct s2io_nic structure */
        store_xmsi_data(sp);
 
        /* After proper initialization of H/W, register ISR */
@@ -6180,7 +6146,7 @@ static int s2io_add_isr(nic_t * sp)
        }
        return 0;
 }
-static void s2io_rem_isr(nic_t * sp)
+static void s2io_rem_isr(struct s2io_nic * sp)
 {
        int cnt = 0;
        struct net_device *dev = sp->dev;
@@ -6222,10 +6188,10 @@ static void s2io_rem_isr(nic_t * sp)
        } while(cnt < 5);
 }
 
-static void s2io_card_down(nic_t * sp)
+static void s2io_card_down(struct s2io_nic * sp)
 {
        int cnt = 0;
-       XENA_dev_config_t __iomem *bar0 = sp->bar0;
+       struct XENA_dev_config __iomem *bar0 = sp->bar0;
        unsigned long flags;
        register u64 val64 = 0;
 
@@ -6256,7 +6222,8 @@ static void s2io_card_down(nic_t * sp)
                rxd_owner_bit_reset(sp);
 
                val64 = readq(&bar0->adapter_status);
-               if (verify_xena_quiescence(sp, val64, sp->device_enabled_once)) {
+               if (verify_xena_quiescence(sp)) {
+                       if(verify_pcc_quiescent(sp, sp->device_enabled_once))
                        break;
                }
 
@@ -6285,10 +6252,10 @@ static void s2io_card_down(nic_t * sp)
        clear_bit(0, &(sp->link_state));
 }
 
-static int s2io_card_up(nic_t * sp)
+static int s2io_card_up(struct s2io_nic * sp)
 {
        int i, ret = 0;
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
        struct net_device *dev = (struct net_device *) sp->dev;
        u16 interruptible;
@@ -6319,6 +6286,13 @@ static int s2io_card_up(nic_t * sp)
                DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
                          atomic_read(&sp->rx_bufs_left[i]));
        }
+       /* Maintain the state prior to the open */
+       if (sp->promisc_flg)
+               sp->promisc_flg = 0;
+       if (sp->m_cast_flg) {
+               sp->m_cast_flg = 0;
+               sp->all_multi_pos= 0;
+       }
 
        /* Setting its receive mode */
        s2io_set_multicast(dev);
@@ -6380,7 +6354,7 @@ static int s2io_card_up(nic_t * sp)
 
 static void s2io_restart_nic(struct work_struct *work)
 {
-       nic_t *sp = container_of(work, nic_t, rst_timer_task);
+       struct s2io_nic *sp = container_of(work, struct s2io_nic, rst_timer_task);
        struct net_device *dev = sp->dev;
 
        s2io_card_down(sp);
@@ -6409,7 +6383,7 @@ static void s2io_restart_nic(struct work_struct *work)
 
 static void s2io_tx_watchdog(struct net_device *dev)
 {
-       nic_t *sp = dev->priv;
+       struct s2io_nic *sp = dev->priv;
 
        if (netif_carrier_ok(dev)) {
                schedule_work(&sp->rst_timer_task);
@@ -6434,16 +6408,16 @@ static void s2io_tx_watchdog(struct net_device *dev)
  *   Return value:
  *   SUCCESS on success and -1 on failure.
  */
-static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
+static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
 {
-       nic_t *sp = ring_data->nic;
+       struct s2io_nic *sp = ring_data->nic;
        struct net_device *dev = (struct net_device *) sp->dev;
        struct sk_buff *skb = (struct sk_buff *)
                ((unsigned long) rxdp->Host_Control);
        int ring_no = ring_data->ring_no;
        u16 l3_csum, l4_csum;
        unsigned long long err = rxdp->Control_1 & RXD_T_CODE;
-       lro_t *lro;
+       struct lro *lro;
 
        skb->dev = dev;
 
@@ -6488,7 +6462,7 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
                int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
                unsigned char *buff = skb_push(skb, buf0_len);
 
-               buffAdd_t *ba = &ring_data->ba[get_block][get_off];
+               struct buffAdd *ba = &ring_data->ba[get_block][get_off];
                sp->stats.rx_bytes += buf0_len + buf2_len;
                memcpy(buff, ba->ba_0, buf0_len);
 
@@ -6498,7 +6472,6 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
                        skb_put(skb, buf1_len);
                        skb->len += buf2_len;
                        skb->data_len += buf2_len;
-                       skb->truesize += buf2_len;
                        skb_put(skb_shinfo(skb)->frag_list, buf2_len);
                        sp->stats.rx_bytes += buf1_len;
 
@@ -6582,23 +6555,20 @@ static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp)
 
        if (!sp->lro) {
                skb->protocol = eth_type_trans(skb, dev);
-#ifdef CONFIG_S2IO_NAPI
-               if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
-                       /* Queueing the vlan frame to the upper layer */
-                       vlan_hwaccel_receive_skb(skb, sp->vlgrp,
-                               RXD_GET_VLAN_TAG(rxdp->Control_2));
-               } else {
-                       netif_receive_skb(skb);
-               }
-#else
                if (sp->vlgrp && RXD_GET_VLAN_TAG(rxdp->Control_2)) {
                        /* Queueing the vlan frame to the upper layer */
-                       vlan_hwaccel_rx(skb, sp->vlgrp,
-                               RXD_GET_VLAN_TAG(rxdp->Control_2));
+                       if (napi)
+                               vlan_hwaccel_receive_skb(skb, sp->vlgrp,
+                                       RXD_GET_VLAN_TAG(rxdp->Control_2));
+                       else
+                               vlan_hwaccel_rx(skb, sp->vlgrp,
+                                       RXD_GET_VLAN_TAG(rxdp->Control_2));
                } else {
-                       netif_rx(skb);
+                       if (napi)
+                               netif_receive_skb(skb);
+                       else
+                               netif_rx(skb);
                }
-#endif
        } else {
 send_up:
                queue_rx_frame(skb);
@@ -6622,7 +6592,7 @@ aggregate:
  *  void.
  */
 
-static void s2io_link(nic_t * sp, int link)
+static void s2io_link(struct s2io_nic * sp, int link)
 {
        struct net_device *dev = (struct net_device *) sp->dev;
 
@@ -6666,7 +6636,7 @@ static int get_xena_rev_id(struct pci_dev *pdev)
  *  void
  */
 
-static void s2io_init_pci(nic_t * sp)
+static void s2io_init_pci(struct s2io_nic * sp)
 {
        u16 pci_cmd = 0, pcix_cmd = 0;
 
@@ -6699,13 +6669,9 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
                DBG_PRINT(ERR_DBG, "s2io: Default to 8 Rx rings\n");
                rx_ring_num = 8;
        }
-#ifdef CONFIG_S2IO_NAPI
-       if (*dev_intr_type != INTA) {
-               DBG_PRINT(ERR_DBG, "s2io: NAPI cannot be enabled when "
-                         "MSI/MSI-X is enabled. Defaulting to INTA\n");
-               *dev_intr_type = INTA;
-       }
-#endif
+       if (*dev_intr_type != INTA)
+               napi = 0;
+
 #ifndef CONFIG_PCI_MSI
        if (*dev_intr_type != INTA) {
                DBG_PRINT(ERR_DBG, "s2io: This kernel does not support"
@@ -6726,6 +6692,8 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
                                        "Defaulting to INTA\n");
                *dev_intr_type = INTA;
        }
+       if ( (rx_ring_num > 1) && (*dev_intr_type != INTA) )
+               napi = 0;
        if (rx_ring_mode > 3) {
                DBG_PRINT(ERR_DBG, "s2io: Requested ring mode not supported\n");
                DBG_PRINT(ERR_DBG, "s2io: Defaulting to 3-buffer mode\n");
@@ -6751,15 +6719,15 @@ static int s2io_verify_parm(struct pci_dev *pdev, u8 *dev_intr_type)
 static int __devinit
 s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 {
-       nic_t *sp;
+       struct s2io_nic *sp;
        struct net_device *dev;
        int i, j, ret;
        int dma_flag = FALSE;
        u32 mac_up, mac_down;
        u64 val64 = 0, tmp64 = 0;
-       XENA_dev_config_t __iomem *bar0 = NULL;
+       struct XENA_dev_config __iomem *bar0 = NULL;
        u16 subid;
-       mac_info_t *mac_control;
+       struct mac_info *mac_control;
        struct config_param *config;
        int mode;
        u8 dev_intr_type = intr_type;
@@ -6814,7 +6782,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
                }
        }
 
-       dev = alloc_etherdev(sizeof(nic_t));
+       dev = alloc_etherdev(sizeof(struct s2io_nic));
        if (dev == NULL) {
                DBG_PRINT(ERR_DBG, "Device allocation failed\n");
                pci_disable_device(pdev);
@@ -6829,7 +6797,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 
        /*  Private member variable initialized to s2io NIC structure */
        sp = dev->priv;
-       memset(sp, 0, sizeof(nic_t));
+       memset(sp, 0, sizeof(struct s2io_nic));
        sp->dev = dev;
        sp->pdev = pdev;
        sp->high_dma_flag = dma_flag;
@@ -6925,7 +6893,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        sp->bar0 = ioremap(pci_resource_start(pdev, 0),
                                     pci_resource_len(pdev, 0));
        if (!sp->bar0) {
-               DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem1\n",
+               DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n",
                          dev->name);
                ret = -ENOMEM;
                goto bar0_remap_failed;
@@ -6934,7 +6902,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        sp->bar1 = ioremap(pci_resource_start(pdev, 2),
                                     pci_resource_len(pdev, 2));
        if (!sp->bar1) {
-               DBG_PRINT(ERR_DBG, "%s: S2IO: cannot remap io mem2\n",
+               DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n",
                          dev->name);
                ret = -ENOMEM;
                goto bar1_remap_failed;
@@ -6945,7 +6913,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 
        /* Initializing the BAR1 address as the start of the FIFO pointer. */
        for (j = 0; j < MAX_TX_FIFOS; j++) {
-               mac_control->tx_FIFO_start[j] = (TxFIFO_element_t __iomem *)
+               mac_control->tx_FIFO_start[j] = (struct TxFIFO_element __iomem *)
                    (sp->bar1 + (j * 0x00020000));
        }
 
@@ -6966,10 +6934,8 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
         * will use eth_mac_addr() for  dev->set_mac_address
         * mac address will be set every time dev->open() is called
         */
-#if defined(CONFIG_S2IO_NAPI)
        dev->poll = s2io_poll;
        dev->weight = 32;
-#endif
 
 #ifdef CONFIG_NET_POLL_CONTROLLER
        dev->poll_controller = s2io_netpoll;
@@ -6978,13 +6944,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM;
        if (sp->high_dma_flag == TRUE)
                dev->features |= NETIF_F_HIGHDMA;
-#ifdef NETIF_F_TSO
        dev->features |= NETIF_F_TSO;
-#endif
-#ifdef NETIF_F_TSO6
        dev->features |= NETIF_F_TSO6;
-#endif
-       if (sp->device_type & XFRAME_II_DEVICE) {
+       if ((sp->device_type & XFRAME_II_DEVICE) && (ufo))  {
                dev->features |= NETIF_F_UFO;
                dev->features |= NETIF_F_HW_CSUM;
        }
@@ -7065,9 +7027,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
 
        /* Initialize spinlocks */
        spin_lock_init(&sp->tx_lock);
-#ifndef CONFIG_S2IO_NAPI
-       spin_lock_init(&sp->put_lock);
-#endif
+
+       if (!napi)
+               spin_lock_init(&sp->put_lock);
        spin_lock_init(&sp->rx_lock);
 
        /*
@@ -7098,13 +7060,14 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name,
                  s2io_driver_version);
        DBG_PRINT(ERR_DBG, "%s: MAC ADDR: "
-                         "%02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
+                         "%02x:%02x:%02x:%02x:%02x:%02x", dev->name,
                          sp->def_mac_addr[0].mac_addr[0],
                          sp->def_mac_addr[0].mac_addr[1],
                          sp->def_mac_addr[0].mac_addr[2],
                          sp->def_mac_addr[0].mac_addr[3],
                          sp->def_mac_addr[0].mac_addr[4],
                          sp->def_mac_addr[0].mac_addr[5]);
+       DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num);
        if (sp->device_type & XFRAME_II_DEVICE) {
                mode = s2io_print_pci_mode(sp);
                if (mode < 0) {
@@ -7128,9 +7091,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
                                                dev->name);
                    break;
        }
-#ifdef CONFIG_S2IO_NAPI
-       DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
-#endif
+
+       if (napi)
+               DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name);
        switch(sp->intr_type) {
                case INTA:
                    DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name);
@@ -7145,7 +7108,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
        if (sp->lro)
                DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
                          dev->name);
-
+       if (ufo)
+               DBG_PRINT(ERR_DBG, "%s: UDP Fragmentation Offload(UFO)"
+                                       " enabled\n", dev->name);
        /* Initialize device name */
        sprintf(sp->name, "%s Neterion %s", dev->name, sp->product_name);
 
@@ -7202,7 +7167,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
 {
        struct net_device *dev =
            (struct net_device *) pci_get_drvdata(pdev);
-       nic_t *sp;
+       struct s2io_nic *sp;
 
        if (dev == NULL) {
                DBG_PRINT(ERR_DBG, "Driver Data is NULL!!\n");
@@ -7215,7 +7180,6 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
        free_shared_mem(sp);
        iounmap(sp->bar0);
        iounmap(sp->bar1);
-       pci_disable_device(pdev);
        if (sp->intr_type != MSI_X)
                pci_release_regions(pdev);
        else {
@@ -7226,6 +7190,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev)
        }
        pci_set_drvdata(pdev, NULL);
        free_netdev(dev);
+       pci_disable_device(pdev);
 }
 
 /**
@@ -7244,7 +7209,7 @@ int __init s2io_starter(void)
  * Description: This function is the cleanup routine for the driver. It unregist * ers the driver.
  */
 
-static void s2io_closer(void)
+static __exit void s2io_closer(void)
 {
        pci_unregister_driver(&s2io_driver);
        DBG_PRINT(INIT_DBG, "cleanup done\n");
@@ -7254,7 +7219,7 @@ module_init(s2io_starter);
 module_exit(s2io_closer);
 
 static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
-               struct tcphdr **tcp, RxD_t *rxdp)
+               struct tcphdr **tcp, struct RxD_t *rxdp)
 {
        int ip_off;
        u8 l2_type = (u8)((rxdp->Control_1 >> 37) & 0x7), ip_len;
@@ -7288,7 +7253,7 @@ static int check_L2_lro_capable(u8 *buffer, struct iphdr **ip,
        return 0;
 }
 
-static int check_for_socket_match(lro_t *lro, struct iphdr *ip,
+static int check_for_socket_match(struct lro *lro, struct iphdr *ip,
                                  struct tcphdr *tcp)
 {
        DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7303,7 +7268,7 @@ static inline int get_l4_pyld_length(struct iphdr *ip, struct tcphdr *tcp)
        return(ntohs(ip->tot_len) - (ip->ihl << 2) - (tcp->doff << 2));
 }
 
-static void initiate_new_session(lro_t *lro, u8 *l2h,
+static void initiate_new_session(struct lro *lro, u8 *l2h,
                     struct iphdr *ip, struct tcphdr *tcp, u32 tcp_pyld_len)
 {
        DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7329,12 +7294,12 @@ static void initiate_new_session(lro_t *lro, u8 *l2h,
        lro->in_use = 1;
 }
 
-static void update_L3L4_header(nic_t *sp, lro_t *lro)
+static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro)
 {
        struct iphdr *ip = lro->iph;
        struct tcphdr *tcp = lro->tcph;
        u16 nchk;
-       StatInfo_t *statinfo = sp->mac_control.stats_info;
+       struct stat_block *statinfo = sp->mac_control.stats_info;
        DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
 
        /* Update L3 header */
@@ -7360,7 +7325,7 @@ static void update_L3L4_header(nic_t *sp, lro_t *lro)
        statinfo->sw_stat.num_aggregations++;
 }
 
-static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
+static void aggregate_new_rx(struct lro *lro, struct iphdr *ip,
                struct tcphdr *tcp, u32 l4_pyld)
 {
        DBG_PRINT(INFO_DBG,"%s: Been here...\n", __FUNCTION__);
@@ -7382,7 +7347,7 @@ static void aggregate_new_rx(lro_t *lro, struct iphdr *ip,
        }
 }
 
-static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
+static int verify_l3_l4_lro_capable(struct lro *l_lro, struct iphdr *ip,
                                    struct tcphdr *tcp, u32 tcp_pyld_len)
 {
        u8 *ptr;
@@ -7440,8 +7405,8 @@ static int verify_l3_l4_lro_capable(lro_t *l_lro, struct iphdr *ip,
 }
 
 static int
-s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
-                     RxD_t *rxdp, nic_t *sp)
+s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
+                     struct RxD_t *rxdp, struct s2io_nic *sp)
 {
        struct iphdr *ip;
        struct tcphdr *tcph;
@@ -7458,7 +7423,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
        tcph = (struct tcphdr *)*tcp;
        *tcp_len = get_l4_pyld_length(ip, tcph);
        for (i=0; i<MAX_LRO_SESSIONS; i++) {
-               lro_t *l_lro = &sp->lro0_n[i];
+               struct lro *l_lro = &sp->lro0_n[i];
                if (l_lro->in_use) {
                        if (check_for_socket_match(l_lro, ip, tcph))
                                continue;
@@ -7496,7 +7461,7 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
                }
 
                for (i=0; i<MAX_LRO_SESSIONS; i++) {
-                       lro_t *l_lro = &sp->lro0_n[i];
+                       struct lro *l_lro = &sp->lro0_n[i];
                        if (!(l_lro->in_use)) {
                                *lro = l_lro;
                                ret = 3; /* Begin anew */
@@ -7535,9 +7500,9 @@ s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro,
        return ret;
 }
 
-static void clear_lro_session(lro_t *lro)
+static void clear_lro_session(struct lro *lro)
 {
-       static u16 lro_struct_size = sizeof(lro_t);
+       static u16 lro_struct_size = sizeof(struct lro);
 
        memset(lro, 0, lro_struct_size);
 }
@@ -7547,14 +7512,14 @@ static void queue_rx_frame(struct sk_buff *skb)
        struct net_device *dev = skb->dev;
 
        skb->protocol = eth_type_trans(skb, dev);
-#ifdef CONFIG_S2IO_NAPI
-       netif_receive_skb(skb);
-#else
-       netif_rx(skb);
-#endif
+       if (napi)
+               netif_receive_skb(skb);
+       else
+               netif_rx(skb);
 }
 
-static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
+static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
+                          struct sk_buff *skb,
                           u32 tcp_len)
 {
        struct sk_buff *first = lro->parent;
@@ -7566,6 +7531,7 @@ static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb,
                lro->last_frag->next = skb;
        else
                skb_shinfo(first)->frag_list = skb;
+       first->truesize += skb->truesize;
        lro->last_frag = skb;
        sp->mac_control.stats_info->sw_stat.clubbed_frms_cnt++;
        return;
index 3b0bafd..a5e1a51 100644 (file)
@@ -30,6 +30,8 @@
 #undef SUCCESS
 #define SUCCESS 0
 #define FAILURE -1
+#define S2IO_MINUS_ONE 0xFFFFFFFFFFFFFFFFULL
+#define S2IO_MAX_PCI_CONFIG_SPACE_REINIT 100
 
 #define CHECKBIT(value, nbit) (value & (1 << nbit))
 
@@ -37,7 +39,7 @@
 #define MAX_FLICKER_TIME       60000 /* 60 Secs */
 
 /* Maximum outstanding splits to be configured into xena. */
-typedef enum xena_max_outstanding_splits {
+enum {
        XENA_ONE_SPLIT_TRANSACTION = 0,
        XENA_TWO_SPLIT_TRANSACTION = 1,
        XENA_THREE_SPLIT_TRANSACTION = 2,
@@ -46,7 +48,7 @@ typedef enum xena_max_outstanding_splits {
        XENA_TWELVE_SPLIT_TRANSACTION = 5,
        XENA_SIXTEEN_SPLIT_TRANSACTION = 6,
        XENA_THIRTYTWO_SPLIT_TRANSACTION = 7
-} xena_max_outstanding_splits;
+};
 #define XENA_MAX_OUTSTANDING_SPLITS(n) (n << 4)
 
 /*  OS concerned variables and constants */
@@ -77,7 +79,7 @@ static int debug_level = ERR_DBG;
 #define S2IO_JUMBO_SIZE 9600
 
 /* Driver statistics maintained by driver */
-typedef struct {
+struct swStat {
        unsigned long long single_ecc_errs;
        unsigned long long double_ecc_errs;
        unsigned long long parity_err_cnt;
@@ -92,10 +94,10 @@ typedef struct {
        unsigned long long flush_max_pkts;
        unsigned long long sum_avg_pkts_aggregated;
        unsigned long long num_aggregations;
-} swStat_t;
+};
 
 /* Xpak releated alarm and warnings */
-typedef struct {
+struct xpakStat {
        u64 alarm_transceiver_temp_high;
        u64 alarm_transceiver_temp_low;
        u64 alarm_laser_bias_current_high;
@@ -110,11 +112,11 @@ typedef struct {
        u64 warn_laser_output_power_low;
        u64 xpak_regs_stat;
        u32 xpak_timer_count;
-} xpakStat_t;
+};
 
 
 /* The statistics block of Xena */
-typedef struct stat_block {
+struct stat_block {
 /* Tx MAC statistics counters. */
        __le32 tmac_data_octets;
        __le32 tmac_frms;
@@ -290,9 +292,9 @@ typedef struct stat_block {
        __le32 reserved_14;
        __le32 link_fault_cnt;
        u8  buffer[20];
-       swStat_t sw_stat;
-       xpakStat_t xpak_stat;
-} StatInfo_t;
+       struct swStat sw_stat;
+       struct xpakStat xpak_stat;
+};
 
 /*
  * Structures representing different init time configuration
@@ -315,7 +317,7 @@ static int fifo_map[][MAX_TX_FIFOS] = {
 };
 
 /* Maintains Per FIFO related information. */
-typedef struct tx_fifo_config {
+struct tx_fifo_config {
 #define        MAX_AVAILABLE_TXDS      8192
        u32 fifo_len;           /* specifies len of FIFO upto 8192, ie no of TxDLs */
 /* Priority definition */
@@ -332,11 +334,11 @@ typedef struct tx_fifo_config {
        u8 f_no_snoop;
 #define NO_SNOOP_TXD                0x01
 #define NO_SNOOP_TXD_BUFFER          0x02
-} tx_fifo_config_t;
+};
 
 
 /* Maintains per Ring related information */
-typedef struct rx_ring_config {
+struct rx_ring_config {
        u32 num_rxd;            /*No of RxDs per Rx Ring */
 #define RX_RING_PRI_0               0  /* highest */
 #define RX_RING_PRI_1               1
@@ -357,7 +359,7 @@ typedef struct rx_ring_config {
        u8 f_no_snoop;
 #define NO_SNOOP_RXD                0x01
 #define NO_SNOOP_RXD_BUFFER         0x02
-} rx_ring_config_t;
+};
 
 /* This structure provides contains values of the tunable parameters
  * of the H/W
@@ -367,7 +369,7 @@ struct config_param {
        u32 tx_fifo_num;        /*Number of Tx FIFOs */
 
        u8 fifo_mapping[MAX_TX_FIFOS];
-       tx_fifo_config_t tx_cfg[MAX_TX_FIFOS];  /*Per-Tx FIFO config */
+       struct tx_fifo_config tx_cfg[MAX_TX_FIFOS];     /*Per-Tx FIFO config */
        u32 max_txds;           /*Max no. of Tx buffer descriptor per TxDL */
        u64 tx_intr_type;
        /* Specifies if Tx Intr is UTILZ or PER_LIST type. */
@@ -376,7 +378,7 @@ struct config_param {
        u32 rx_ring_num;        /*Number of receive rings */
 #define MAX_RX_BLOCKS_PER_RING  150
 
-       rx_ring_config_t rx_cfg[MAX_RX_RINGS];  /*Per-Rx Ring config */
+       struct rx_ring_config rx_cfg[MAX_RX_RINGS];     /*Per-Rx Ring config */
        u8 bimodal;             /*Flag for setting bimodal interrupts*/
 
 #define HEADER_ETHERNET_II_802_3_SIZE 14
@@ -395,14 +397,14 @@ struct config_param {
 };
 
 /* Structure representing MAC Addrs */
-typedef struct mac_addr {
+struct mac_addr {
        u8 mac_addr[ETH_ALEN];
-} macaddr_t;
+};
 
 /* Structure that represent every FIFO element in the BAR1
  * Address location.
  */
-typedef struct _TxFIFO_element {
+struct TxFIFO_element {
        u64 TxDL_Pointer;
 
        u64 List_Control;
@@ -413,10 +415,10 @@ typedef struct _TxFIFO_element {
 #define TX_FIFO_SPECIAL_FUNC           BIT(23)
 #define TX_FIFO_DS_NO_SNOOP            BIT(31)
 #define TX_FIFO_BUFF_NO_SNOOP          BIT(30)
-} TxFIFO_element_t;
+};
 
 /* Tx descriptor structure */
-typedef struct _TxD {
+struct TxD {
        u64 Control_1;
 /* bit mask */
 #define TXD_LIST_OWN_XENA       BIT(7)
@@ -447,16 +449,16 @@ typedef struct _TxD {
 
        u64 Buffer_Pointer;
        u64 Host_Control;       /* reserved for host */
-} TxD_t;
+};
 
 /* Structure to hold the phy and virt addr of every TxDL. */
-typedef struct list_info_hold {
+struct list_info_hold {
        dma_addr_t list_phy_addr;
        void *list_virt_addr;
-} list_info_hold_t;
+};
 
 /* Rx descriptor structure for 1 buffer mode */
-typedef struct _RxD_t {
+struct RxD_t {
        u64 Host_Control;       /* reserved for host */
        u64 Control_1;
 #define RXD_OWN_XENA            BIT(7)
@@ -481,21 +483,21 @@ typedef struct _RxD_t {
 #define SET_NUM_TAG(val)       vBIT(val,16,32)
 
 
-} RxD_t;
+};
 /* Rx descriptor structure for 1 buffer mode */
-typedef struct _RxD1_t {
-       struct _RxD_t h;
+struct RxD1 {
+       struct RxD_t h;
 
 #define MASK_BUFFER0_SIZE_1       vBIT(0x3FFF,2,14)
 #define SET_BUFFER0_SIZE_1(val)   vBIT(val,2,14)
 #define RXD_GET_BUFFER0_SIZE_1(_Control_2) \
        (u16)((_Control_2 & MASK_BUFFER0_SIZE_1) >> 48)
        u64 Buffer0_ptr;
-} RxD1_t;
+};
 /* Rx descriptor structure for 3 or 2 buffer mode */
 
-typedef struct _RxD3_t {
-       struct _RxD_t h;
+struct RxD3 {
+       struct RxD_t h;
 
 #define MASK_BUFFER0_SIZE_3       vBIT(0xFF,2,14)
 #define MASK_BUFFER1_SIZE_3       vBIT(0xFFFF,16,16)
@@ -515,15 +517,15 @@ typedef struct _RxD3_t {
        u64 Buffer0_ptr;
        u64 Buffer1_ptr;
        u64 Buffer2_ptr;
-} RxD3_t;
+};
 
 
 /* Structure that represents the Rx descriptor block which contains
  * 128 Rx descriptors.
  */
-typedef struct _RxD_block {
+struct RxD_block {
 #define MAX_RXDS_PER_BLOCK_1            127
-       RxD1_t rxd[MAX_RXDS_PER_BLOCK_1];
+       struct RxD1 rxd[MAX_RXDS_PER_BLOCK_1];
 
        u64 reserved_0;
 #define END_OF_BLOCK    0xFEFFFFFFFFFFFFFFULL
@@ -533,22 +535,22 @@ typedef struct _RxD_block {
        u64 pNext_RxD_Blk_physical;     /* Buff0_ptr.In a 32 bit arch
                                         * the upper 32 bits should
                                         * be 0 */
-} RxD_block_t;
+};
 
 #define SIZE_OF_BLOCK  4096
 
-#define RXD_MODE_1     0
-#define RXD_MODE_3A    1
-#define RXD_MODE_3B    2
+#define RXD_MODE_1     0 /* One Buffer mode */
+#define RXD_MODE_3A    1 /* Three Buffer mode */
+#define RXD_MODE_3B    2 /* Two Buffer mode */
 
 /* Structure to hold virtual addresses of Buf0 and Buf1 in
  * 2buf mode. */
-typedef struct bufAdd {
+struct buffAdd {
        void *ba_0_org;
        void *ba_1_org;
        void *ba_0;
        void *ba_1;
-} buffAdd_t;
+};
 
 /* Structure which stores all the MAC control parameters */
 
@@ -556,43 +558,46 @@ typedef struct bufAdd {
  * from which the Rx Interrupt processor can start picking
  * up the RxDs for processing.
  */
-typedef struct _rx_curr_get_info_t {
+struct rx_curr_get_info {
        u32 block_index;
        u32 offset;
        u32 ring_len;
-} rx_curr_get_info_t;
+};
 
-typedef rx_curr_get_info_t rx_curr_put_info_t;
+struct rx_curr_put_info {
+       u32 block_index;
+       u32 offset;
+       u32 ring_len;
+};
 
 /* This structure stores the offset of the TxDl in the FIFO
  * from which the Tx Interrupt processor can start picking
  * up the TxDLs for send complete interrupt processing.
  */
-typedef struct {
+struct tx_curr_get_info {
        u32 offset;
        u32 fifo_len;
-} tx_curr_get_info_t;
-
-typedef tx_curr_get_info_t tx_curr_put_info_t;
+};
 
+struct tx_curr_put_info {
+       u32 offset;
+       u32 fifo_len;
+};
 
-typedef struct rxd_info {
+struct rxd_info {
        void *virt_addr;
        dma_addr_t dma_addr;
-}rxd_info_t;
+};
 
 /* Structure that holds the Phy and virt addresses of the Blocks */
-typedef struct rx_block_info {
+struct rx_block_info {
        void *block_virt_addr;
        dma_addr_t block_dma_addr;
-       rxd_info_t *rxds;
-} rx_block_info_t;
-
-/* pre declaration of the nic structure */
-typedef struct s2io_nic nic_t;
+       struct rxd_info *rxds;
+};
 
 /* Ring specific structure */
-typedef struct ring_info {
+struct ring_info {
        /* The ring number */
        int ring_no;
 
@@ -600,7 +605,7 @@ typedef struct ring_info {
         *  Place holders for the virtual and physical addresses of
         *  all the Rx Blocks
         */
-       rx_block_info_t rx_blocks[MAX_RX_BLOCKS_PER_RING];
+       struct rx_block_info rx_blocks[MAX_RX_BLOCKS_PER_RING];
        int block_count;
        int pkt_cnt;
 
@@ -608,26 +613,24 @@ typedef struct ring_info {
         * Put pointer info which indictes which RxD has to be replenished
         * with a new buffer.
         */
-       rx_curr_put_info_t rx_curr_put_info;
+       struct rx_curr_put_info rx_curr_put_info;
 
        /*
         * Get pointer info which indictes which is the last RxD that was
         * processed by the driver.
         */
-       rx_curr_get_info_t rx_curr_get_info;
+       struct rx_curr_get_info rx_curr_get_info;
 
-#ifndef CONFIG_S2IO_NAPI
        /* Index to the absolute position of the put pointer of Rx ring */
        int put_pos;
-#endif
 
        /* Buffer Address store. */
-       buffAdd_t **ba;
-       nic_t *nic;
-} ring_info_t;
+       struct buffAdd **ba;
+       struct s2io_nic *nic;
+};
 
 /* Fifo specific structure */
-typedef struct fifo_info {
+struct fifo_info {
        /* FIFO number */
        int fifo_no;
 
@@ -635,40 +638,40 @@ typedef struct fifo_info {
        int max_txds;
 
        /* Place holder of all the TX List's Phy and Virt addresses. */
-       list_info_hold_t *list_info;
+       struct list_info_hold *list_info;
 
        /*
         * Current offset within the tx FIFO where driver would write
         * new Tx frame
         */
-       tx_curr_put_info_t tx_curr_put_info;
+       struct tx_curr_put_info tx_curr_put_info;
 
        /*
         * Current offset within tx FIFO from where the driver would start freeing
         * the buffers
         */
-       tx_curr_get_info_t tx_curr_get_info;
+       struct tx_curr_get_info tx_curr_get_info;
 
-       nic_t *nic;
-}fifo_info_t;
+       struct s2io_nic *nic;
+};
 
 /* Information related to the Tx and Rx FIFOs and Rings of Xena
  * is maintained in this structure.
  */
-typedef struct mac_info {
+struct mac_info {
 /* tx side stuff */
        /* logical pointer of start of each Tx FIFO */
-       TxFIFO_element_t __iomem *tx_FIFO_start[MAX_TX_FIFOS];
+       struct TxFIFO_element __iomem *tx_FIFO_start[MAX_TX_FIFOS];
 
        /* Fifo specific structure */
-       fifo_info_t fifos[MAX_TX_FIFOS];
+       struct fifo_info fifos[MAX_TX_FIFOS];
 
        /* Save virtual address of TxD page with zero DMA addr(if any) */
        void *zerodma_virt_addr;
 
 /* rx side stuff */
        /* Ring specific structure */
-       ring_info_t rings[MAX_RX_RINGS];
+       struct ring_info rings[MAX_RX_RINGS];
 
        u16 rmac_pause_time;
        u16 mc_pause_threshold_q0q3;
@@ -677,14 +680,14 @@ typedef struct mac_info {
        void *stats_mem;        /* orignal pointer to allocated mem */
        dma_addr_t stats_mem_phy;       /* Physical address of the stat block */
        u32 stats_mem_sz;
-       StatInfo_t *stats_info; /* Logical address of the stat block */
-} mac_info_t;
+       struct stat_block *stats_info;  /* Logical address of the stat block */
+};
 
 /* structure representing the user defined MAC addresses */
-typedef struct {
+struct usr_addr {
        char addr[ETH_ALEN];
        int usage_cnt;
-} usr_addr_t;
+};
 
 /* Default Tunable parameters of the NIC. */
 #define DEFAULT_FIFO_0_LEN 4096
@@ -717,7 +720,7 @@ struct msix_info_st {
 };
 
 /* Data structure to represent a LRO session */
-typedef struct lro {
+struct lro {
        struct sk_buff  *parent;
        struct sk_buff  *last_frag;
        u8              *l2h;
@@ -733,20 +736,18 @@ typedef struct lro {
        u32             cur_tsval;
        u32             cur_tsecr;
        u8              saw_ts;
-}lro_t;
+};
 
 /* Structure representing one instance of the NIC */
 struct s2io_nic {
        int rxd_mode;
-#ifdef CONFIG_S2IO_NAPI
        /*
         * Count of packets to be processed in a given iteration, it will be indicated
         * by the quota field of the device structure when NAPI is enabled.
         */
        int pkts_to_process;
-#endif
        struct net_device *dev;
-       mac_info_t mac_control;
+       struct mac_info mac_control;
        struct config_param config;
        struct pci_dev *pdev;
        void __iomem *bar0;
@@ -754,8 +755,8 @@ struct s2io_nic {
 #define MAX_MAC_SUPPORTED   16
 #define MAX_SUPPORTED_MULTICASTS MAX_MAC_SUPPORTED
 
-       macaddr_t def_mac_addr[MAX_MAC_SUPPORTED];
-       macaddr_t pre_mac_addr[MAX_MAC_SUPPORTED];
+       struct mac_addr def_mac_addr[MAX_MAC_SUPPORTED];
+       struct mac_addr pre_mac_addr[MAX_MAC_SUPPORTED];
 
        struct net_device_stats stats;
        int high_dma_flag;
@@ -775,9 +776,7 @@ struct s2io_nic {
        atomic_t rx_bufs_left[MAX_RX_RINGS];
 
        spinlock_t tx_lock;
-#ifndef CONFIG_S2IO_NAPI
        spinlock_t put_lock;
-#endif
 
 #define PROMISC     1
 #define ALL_MULTI   2
@@ -785,7 +784,7 @@ struct s2io_nic {
 #define MAX_ADDRS_SUPPORTED 64
        u16 usr_addr_count;
        u16 mc_addr_count;
-       usr_addr_t usr_addrs[MAX_ADDRS_SUPPORTED];
+       struct usr_addr usr_addrs[MAX_ADDRS_SUPPORTED];
 
        u16 m_cast_flg;
        u16 all_multi_pos;
@@ -841,7 +840,7 @@ struct s2io_nic {
        u8 device_type;
 
 #define MAX_LRO_SESSIONS       32
-       lro_t lro0_n[MAX_LRO_SESSIONS];
+       struct lro lro0_n[MAX_LRO_SESSIONS];
        unsigned long   clubbed_frms_cnt;
        unsigned long   sending_both;
        u8              lro;
@@ -855,8 +854,9 @@ struct s2io_nic {
        spinlock_t      rx_lock;
        atomic_t        isr_cnt;
        u64 *ufo_in_band_v;
-#define VPD_PRODUCT_NAME_LEN 50
-       u8  product_name[VPD_PRODUCT_NAME_LEN];
+#define VPD_STRING_LEN 80
+       u8  product_name[VPD_STRING_LEN];
+       u8  serial_num[VPD_STRING_LEN];
 };
 
 #define RESET_ERROR 1;
@@ -975,43 +975,50 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev);
 static int init_shared_mem(struct s2io_nic *sp);
 static void free_shared_mem(struct s2io_nic *sp);
 static int init_nic(struct s2io_nic *nic);
-static void rx_intr_handler(ring_info_t *ring_data);
-static void tx_intr_handler(fifo_info_t *fifo_data);
+static void rx_intr_handler(struct ring_info *ring_data);
+static void tx_intr_handler(struct fifo_info *fifo_data);
 static void alarm_intr_handler(struct s2io_nic *sp);
 
 static int s2io_starter(void);
+static void s2io_closer(void);
 static void s2io_tx_watchdog(struct net_device *dev);
 static void s2io_tasklet(unsigned long dev_addr);
 static void s2io_set_multicast(struct net_device *dev);
-static int rx_osm_handler(ring_info_t *ring_data, RxD_t * rxdp);
-static void s2io_link(nic_t * sp, int link);
-#if defined(CONFIG_S2IO_NAPI)
+static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp);
+static void s2io_link(struct s2io_nic * sp, int link);
+static void s2io_reset(struct s2io_nic * sp);
 static int s2io_poll(struct net_device *dev, int *budget);
-#endif
-static void s2io_init_pci(nic_t * sp);
+static void s2io_init_pci(struct s2io_nic * sp);
 static int s2io_set_mac_addr(struct net_device *dev, u8 * addr);
 static void s2io_alarm_handle(unsigned long data);
-static int s2io_enable_msi(nic_t *nic);
+static int s2io_enable_msi(struct s2io_nic *nic);
 static irqreturn_t s2io_msi_handle(int irq, void *dev_id);
 static irqreturn_t
 s2io_msix_ring_handle(int irq, void *dev_id);
 static irqreturn_t
 s2io_msix_fifo_handle(int irq, void *dev_id);
 static irqreturn_t s2io_isr(int irq, void *dev_id);
-static int verify_xena_quiescence(nic_t *sp, u64 val64, int flag);
+static int verify_xena_quiescence(struct s2io_nic *sp);
 static const struct ethtool_ops netdev_ethtool_ops;
 static void s2io_set_link(struct work_struct *work);
-static int s2io_set_swapper(nic_t * sp);
-static void s2io_card_down(nic_t *nic);
-static int s2io_card_up(nic_t *nic);
+static int s2io_set_swapper(struct s2io_nic * sp);
+static void s2io_card_down(struct s2io_nic *nic);
+static int s2io_card_up(struct s2io_nic *nic);
 static int get_xena_rev_id(struct pci_dev *pdev);
-static void restore_xmsi_data(nic_t *nic);
+static int wait_for_cmd_complete(void *addr, u64 busy_bit);
+static int s2io_add_isr(struct s2io_nic * sp);
+static void s2io_rem_isr(struct s2io_nic * sp);
+
+static void restore_xmsi_data(struct s2io_nic *nic);
 
-static int s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, lro_t **lro, RxD_t *rxdp, nic_t *sp);
-static void clear_lro_session(lro_t *lro);
+static int
+s2io_club_tcp_session(u8 *buffer, u8 **tcp, u32 *tcp_len, struct lro **lro,
+                     struct RxD_t *rxdp, struct s2io_nic *sp);
+static void clear_lro_session(struct lro *lro);
 static void queue_rx_frame(struct sk_buff *skb);
-static void update_L3L4_header(nic_t *sp, lro_t *lro);
-static void lro_append_pkt(nic_t *sp, lro_t *lro, struct sk_buff *skb, u32 tcp_len);
+static void update_L3L4_header(struct s2io_nic *sp, struct lro *lro);
+static void lro_append_pkt(struct s2io_nic *sp, struct lro *lro,
+                          struct sk_buff *skb, u32 tcp_len);
 
 #define s2io_tcp_mss(skb) skb_shinfo(skb)->gso_size
 #define s2io_udp_mss(skb) skb_shinfo(skb)->gso_size
diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c
new file mode 100644 (file)
index 0000000..7f800fe
--- /dev/null
@@ -0,0 +1,1620 @@
+/*  Silan SC92031 PCI Fast Ethernet Adapter driver
+ *
+ *  Based on vendor drivers:
+ *  Silan Fast Ethernet Netcard Driver:
+ *    MODULE_AUTHOR ("gaoyonghong");
+ *    MODULE_DESCRIPTION ("SILAN Fast Ethernet driver");
+ *    MODULE_LICENSE("GPL");
+ *  8139D Fast Ethernet driver:
+ *    (C) 2002 by gaoyonghong
+ *    MODULE_AUTHOR ("gaoyonghong");
+ *    MODULE_DESCRIPTION ("Rsltek 8139D PCI Fast Ethernet Adapter driver");
+ *    MODULE_LICENSE("GPL");
+ *  Both are almost identical and seem to be based on pci-skeleton.c
+ *
+ *  Rewritten for 2.6 by Cesar Eduardo Barros
+ */
+
+/* Note about set_mac_address: I don't know how to change the hardware
+ * matching, so you need to enable IFF_PROMISC when using it.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/crc32.h>
+
+#include <asm/irq.h>
+
+#define PCI_VENDOR_ID_SILAN            0x1904
+#define PCI_DEVICE_ID_SILAN_SC92031    0x2031
+#define PCI_DEVICE_ID_SILAN_8139D      0x8139
+
+#define SC92031_NAME "sc92031"
+#define SC92031_DESCRIPTION "Silan SC92031 PCI Fast Ethernet Adapter driver"
+#define SC92031_VERSION "2.0c"
+
+/* BAR 0 is MMIO, BAR 1 is PIO */
+#ifndef SC92031_USE_BAR
+#define SC92031_USE_BAR 0
+#endif
+
+/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */
+static int multicast_filter_limit = 64;
+module_param(multicast_filter_limit, int, 0);
+MODULE_PARM_DESC(multicast_filter_limit,
+       "Maximum number of filtered multicast addresses");
+
+static int media;
+module_param(media, int, 0);
+MODULE_PARM_DESC(media, "Media type (0x00 = autodetect,"
+       " 0x01 = 10M half, 0x02 = 10M full,"
+       " 0x04 = 100M half, 0x08 = 100M full)");
+
+/* Size of the in-memory receive ring. */
+#define  RX_BUF_LEN_IDX  3 /* 0==8K, 1==16K, 2==32K, 3==64K ,4==128K*/
+#define  RX_BUF_LEN    (8192 << RX_BUF_LEN_IDX)
+
+/* Number of Tx descriptor registers. */
+#define  NUM_TX_DESC      4
+
+/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/
+#define  MAX_ETH_FRAME_SIZE      1536
+
+/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */
+#define  TX_BUF_SIZE       MAX_ETH_FRAME_SIZE
+#define  TX_BUF_TOT_LEN    (TX_BUF_SIZE * NUM_TX_DESC)
+
+/* The following settings are log_2(bytes)-4:  0 == 16 bytes .. 6==1024, 7==end of packet. */
+#define  RX_FIFO_THRESH    7     /* Rx buffer level before first PCI xfer.  */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define  TX_TIMEOUT     (4*HZ)
+
+#define  SILAN_STATS_NUM    2    /* number of ETHTOOL_GSTATS */
+
+/* media options */
+#define  AUTOSELECT    0x00
+#define  M10_HALF      0x01
+#define  M10_FULL      0x02
+#define  M100_HALF     0x04
+#define  M100_FULL     0x08
+
+ /* Symbolic offsets to registers. */
+enum  silan_registers {
+   Config0    = 0x00,         // Config0
+   Config1    = 0x04,         // Config1
+   RxBufWPtr  = 0x08,         // Rx buffer writer poiter
+   IntrStatus = 0x0C,         // Interrupt status
+   IntrMask   = 0x10,         // Interrupt mask
+   RxbufAddr  = 0x14,         // Rx buffer start address
+   RxBufRPtr  = 0x18,         // Rx buffer read pointer
+   Txstatusall = 0x1C,        // Transmit status of all descriptors
+   TxStatus0  = 0x20,        // Transmit status (Four 32bit registers).
+   TxAddr0    = 0x30,         // Tx descriptors (also four 32bit).
+   RxConfig   = 0x40,         // Rx configuration
+   MAC0              = 0x44,         // Ethernet hardware address.
+   MAR0              = 0x4C,         // Multicast filter.
+   RxStatus0  = 0x54,         // Rx status
+   TxConfig   = 0x5C,         // Tx configuration
+   PhyCtrl    = 0x60,         // physical control
+   FlowCtrlConfig = 0x64,     // flow control
+   Miicmd0    = 0x68,         // Mii command0 register
+   Miicmd1    = 0x6C,         // Mii command1 register
+   Miistatus  = 0x70,         // Mii status register
+   Timercnt   = 0x74,         // Timer counter register
+   TimerIntr  = 0x78,         // Timer interrupt register
+   PMConfig   = 0x7C,         // Power Manager configuration
+   CRC0       = 0x80,         // Power Manager CRC ( Two 32bit regisers)
+   Wakeup0    = 0x88,         // power Manager wakeup( Eight 64bit regiser)
+   LSBCRC0    = 0xC8,         // power Manager LSBCRC(Two 32bit regiser)
+   TestD0     = 0xD0,
+   TestD4     = 0xD4,
+   TestD8     = 0xD8,
+};
+
+#define MII_BMCR            0        // Basic mode control register
+#define MII_BMSR            1        // Basic mode status register
+#define MII_JAB             16
+#define MII_OutputStatus    24
+
+#define BMCR_FULLDPLX       0x0100    // Full duplex
+#define BMCR_ANRESTART      0x0200    // Auto negotiation restart
+#define BMCR_ANENABLE       0x1000    // Enable auto negotiation
+#define BMCR_SPEED100       0x2000    // Select 100Mbps
+#define BMSR_LSTATUS        0x0004    // Link status
+#define PHY_16_JAB_ENB      0x1000
+#define PHY_16_PORT_ENB     0x1
+
+enum IntrStatusBits {
+   LinkFail       = 0x80000000,
+   LinkOK         = 0x40000000,
+   TimeOut        = 0x20000000,
+   RxOverflow     = 0x0040,
+   RxOK           = 0x0020,
+   TxOK           = 0x0001,
+   IntrBits = LinkFail|LinkOK|TimeOut|RxOverflow|RxOK|TxOK,
+};
+
+enum TxStatusBits {
+   TxCarrierLost = 0x20000000,
+   TxAborted     = 0x10000000,
+   TxOutOfWindow = 0x08000000,
+   TxNccShift    = 22,
+   EarlyTxThresShift = 16,
+   TxStatOK      = 0x8000,
+   TxUnderrun    = 0x4000,
+   TxOwn         = 0x2000,
+};
+
+enum RxStatusBits {
+   RxStatesOK   = 0x80000,
+   RxBadAlign   = 0x40000,
+   RxHugeFrame  = 0x20000,
+   RxSmallFrame = 0x10000,
+   RxCRCOK      = 0x8000,
+   RxCrlFrame   = 0x4000,
+   Rx_Broadcast = 0x2000,
+   Rx_Multicast = 0x1000,
+   RxAddrMatch  = 0x0800,
+   MiiErr       = 0x0400,
+};
+
+enum RxConfigBits {
+   RxFullDx    = 0x80000000,
+   RxEnb       = 0x40000000,
+   RxSmall     = 0x20000000,
+   RxHuge      = 0x10000000,
+   RxErr       = 0x08000000,
+   RxAllphys   = 0x04000000,
+   RxMulticast = 0x02000000,
+   RxBroadcast = 0x01000000,
+   RxLoopBack  = (1 << 23) | (1 << 22),
+   LowThresholdShift  = 12,
+   HighThresholdShift = 2,
+};
+
+enum TxConfigBits {
+   TxFullDx       = 0x80000000,
+   TxEnb          = 0x40000000,
+   TxEnbPad       = 0x20000000,
+   TxEnbHuge      = 0x10000000,
+   TxEnbFCS       = 0x08000000,
+   TxNoBackOff    = 0x04000000,
+   TxEnbPrem      = 0x02000000,
+   TxCareLostCrs  = 0x1000000,
+   TxExdCollNum   = 0xf00000,
+   TxDataRate     = 0x80000,
+};
+
+enum PhyCtrlconfigbits {
+   PhyCtrlAne         = 0x80000000,
+   PhyCtrlSpd100      = 0x40000000,
+   PhyCtrlSpd10       = 0x20000000,
+   PhyCtrlPhyBaseAddr = 0x1f000000,
+   PhyCtrlDux         = 0x800000,
+   PhyCtrlReset       = 0x400000,
+};
+
+enum FlowCtrlConfigBits {
+   FlowCtrlFullDX = 0x80000000,
+   FlowCtrlEnb    = 0x40000000,
+};
+
+enum Config0Bits {
+   Cfg0_Reset  = 0x80000000,
+   Cfg0_Anaoff = 0x40000000,
+   Cfg0_LDPS   = 0x20000000,
+};
+
+enum Config1Bits {
+   Cfg1_EarlyRx = 1 << 31,
+   Cfg1_EarlyTx = 1 << 30,
+
+   //rx buffer size
+   Cfg1_Rcv8K   = 0x0,
+   Cfg1_Rcv16K  = 0x1,
+   Cfg1_Rcv32K  = 0x3,
+   Cfg1_Rcv64K  = 0x7,
+   Cfg1_Rcv128K = 0xf,
+};
+
+enum MiiCmd0Bits {
+   Mii_Divider = 0x20000000,
+   Mii_WRITE   = 0x400000,
+   Mii_READ    = 0x200000,
+   Mii_SCAN    = 0x100000,
+   Mii_Tamod   = 0x80000,
+   Mii_Drvmod  = 0x40000,
+   Mii_mdc     = 0x20000,
+   Mii_mdoen   = 0x10000,
+   Mii_mdo     = 0x8000,
+   Mii_mdi     = 0x4000,
+};
+
+enum MiiStatusBits {
+    Mii_StatusBusy = 0x80000000,
+};
+
+enum PMConfigBits {
+   PM_Enable  = 1 << 31,
+   PM_LongWF  = 1 << 30,
+   PM_Magic   = 1 << 29,
+   PM_LANWake = 1 << 28,
+   PM_LWPTN   = (1 << 27 | 1<< 26),
+   PM_LinkUp  = 1 << 25,
+   PM_WakeUp  = 1 << 24,
+};
+
+/* Locking rules:
+ * priv->lock protects most of the fields of priv and most of the
+ * hardware registers. It does not have to protect against softirqs
+ * between sc92031_disable_interrupts and sc92031_enable_interrupts;
+ * it also does not need to be used in ->open and ->stop while the
+ * device interrupts are off.
+ * Not having to protect against softirqs is very useful due to heavy
+ * use of mdelay() at _sc92031_reset.
+ * Functions prefixed with _sc92031_ must be called with the lock held;
+ * functions prefixed with sc92031_ must be called without the lock held.
+ * Use mmiowb() before unlocking if the hardware was written to.
+ */
+
+/* Locking rules for the interrupt:
+ * - the interrupt and the tasklet never run at the same time
+ * - neither run between sc92031_disable_interrupts and
+ *   sc92031_enable_interrupt
+ */
+
+struct sc92031_priv {
+       spinlock_t              lock;
+       /* iomap.h cookie */
+       void __iomem            *port_base;
+       /* pci device structure */
+       struct pci_dev          *pdev;
+       /* tasklet */
+       struct tasklet_struct   tasklet;
+
+       /* CPU address of rx ring */
+       void                    *rx_ring;
+       /* PCI address of rx ring */
+       dma_addr_t              rx_ring_dma_addr;
+       /* PCI address of rx ring read pointer */
+       dma_addr_t              rx_ring_tail;
+
+       /* tx ring write index */
+       unsigned                tx_head;
+       /* tx ring read index */
+       unsigned                tx_tail;
+       /* CPU address of tx bounce buffer */
+       void                    *tx_bufs;
+       /* PCI address of tx bounce buffer */
+       dma_addr_t              tx_bufs_dma_addr;
+
+       /* copies of some hardware registers */
+       u32                     intr_status;
+       atomic_t                intr_mask;
+       u32                     rx_config;
+       u32                     tx_config;
+       u32                     pm_config;
+
+       /* copy of some flags from dev->flags */
+       unsigned int            mc_flags;
+
+       /* for ETHTOOL_GSTATS */
+       u64                     tx_timeouts;
+       u64                     rx_loss;
+
+       /* for dev->get_stats */
+       long                    rx_value;
+       struct net_device_stats stats;
+};
+
+/* I don't know which registers can be safely read; however, I can guess
+ * MAC0 is one of them. */
+static inline void _sc92031_dummy_read(void __iomem *port_base)
+{
+       ioread32(port_base + MAC0);
+}
+
+static u32 _sc92031_mii_wait(void __iomem *port_base)
+{
+       u32 mii_status;
+
+       do {
+               udelay(10);
+               mii_status = ioread32(port_base + Miistatus);
+       } while (mii_status & Mii_StatusBusy);
+
+       return mii_status;
+}
+
+static u32 _sc92031_mii_cmd(void __iomem *port_base, u32 cmd0, u32 cmd1)
+{
+       iowrite32(Mii_Divider, port_base + Miicmd0);
+
+       _sc92031_mii_wait(port_base);
+
+       iowrite32(cmd1, port_base + Miicmd1);
+       iowrite32(Mii_Divider | cmd0, port_base + Miicmd0);
+
+       return _sc92031_mii_wait(port_base);
+}
+
+static void _sc92031_mii_scan(void __iomem *port_base)
+{
+       _sc92031_mii_cmd(port_base, Mii_SCAN, 0x1 << 6);
+}
+
+static u16 _sc92031_mii_read(void __iomem *port_base, unsigned reg)
+{
+       return _sc92031_mii_cmd(port_base, Mii_READ, reg << 6) >> 13;
+}
+
+static void _sc92031_mii_write(void __iomem *port_base, unsigned reg, u16 val)
+{
+       _sc92031_mii_cmd(port_base, Mii_WRITE, (reg << 6) | ((u32)val << 11));
+}
+
+static void sc92031_disable_interrupts(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+
+       /* tell the tasklet/interrupt not to enable interrupts */
+       atomic_set(&priv->intr_mask, 0);
+       wmb();
+
+       /* stop interrupts */
+       iowrite32(0, port_base + IntrMask);
+       _sc92031_dummy_read(port_base);
+       mmiowb();
+
+       /* wait for any concurrent interrupt/tasklet to finish */
+       synchronize_irq(dev->irq);
+       tasklet_disable(&priv->tasklet);
+}
+
+static void sc92031_enable_interrupts(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+
+       tasklet_enable(&priv->tasklet);
+
+       atomic_set(&priv->intr_mask, IntrBits);
+       wmb();
+
+       iowrite32(IntrBits, port_base + IntrMask);
+       mmiowb();
+}
+
+static void _sc92031_disable_tx_rx(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+
+       priv->rx_config &= ~RxEnb;
+       priv->tx_config &= ~TxEnb;
+       iowrite32(priv->rx_config, port_base + RxConfig);
+       iowrite32(priv->tx_config, port_base + TxConfig);
+}
+
+static void _sc92031_enable_tx_rx(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+
+       priv->rx_config |= RxEnb;
+       priv->tx_config |= TxEnb;
+       iowrite32(priv->rx_config, port_base + RxConfig);
+       iowrite32(priv->tx_config, port_base + TxConfig);
+}
+
+static void _sc92031_tx_clear(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+
+       while (priv->tx_head - priv->tx_tail > 0) {
+               priv->tx_tail++;
+               priv->stats.tx_dropped++;
+       }
+       priv->tx_head = priv->tx_tail = 0;
+}
+
+static void _sc92031_set_mar(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+       u32 mar0 = 0, mar1 = 0;
+
+       if ((dev->flags & IFF_PROMISC)
+                       || dev->mc_count > multicast_filter_limit
+                       || (dev->flags & IFF_ALLMULTI))
+               mar0 = mar1 = 0xffffffff;
+       else if (dev->flags & IFF_MULTICAST) {
+               struct dev_mc_list *mc_list;
+
+               for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) {
+                       u32 crc;
+                       unsigned bit = 0;
+
+                       crc = ~ether_crc(ETH_ALEN, mc_list->dmi_addr);
+                       crc >>= 24;
+
+                       if (crc & 0x01) bit |= 0x02;
+                       if (crc & 0x02) bit |= 0x01;
+                       if (crc & 0x10) bit |= 0x20;
+                       if (crc & 0x20) bit |= 0x10;
+                       if (crc & 0x40) bit |= 0x08;
+                       if (crc & 0x80) bit |= 0x04;
+
+                       if (bit > 31)
+                               mar0 |= 0x1 << (bit - 32);
+                       else
+                               mar1 |= 0x1 << bit;
+               }
+       }
+
+       iowrite32(mar0, port_base + MAR0);
+       iowrite32(mar1, port_base + MAR0 + 4);
+}
+
+static void _sc92031_set_rx_config(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+       unsigned int old_mc_flags;
+       u32 rx_config_bits = 0;
+
+       old_mc_flags = priv->mc_flags;
+
+       if (dev->flags & IFF_PROMISC)
+               rx_config_bits |= RxSmall | RxHuge | RxErr | RxBroadcast
+                               | RxMulticast | RxAllphys;
+
+       if (dev->flags & (IFF_ALLMULTI | IFF_MULTICAST))
+               rx_config_bits |= RxMulticast;
+
+       if (dev->flags & IFF_BROADCAST)
+               rx_config_bits |= RxBroadcast;
+
+       priv->rx_config &= ~(RxSmall | RxHuge | RxErr | RxBroadcast
+                       | RxMulticast | RxAllphys);
+       priv->rx_config |= rx_config_bits;
+
+       priv->mc_flags = dev->flags & (IFF_PROMISC | IFF_ALLMULTI
+                       | IFF_MULTICAST | IFF_BROADCAST);
+
+       if (netif_carrier_ok(dev) && priv->mc_flags != old_mc_flags)
+               iowrite32(priv->rx_config, port_base + RxConfig);
+}
+
+static bool _sc92031_check_media(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+       u16 bmsr;
+
+       bmsr = _sc92031_mii_read(port_base, MII_BMSR);
+       rmb();
+       if (bmsr & BMSR_LSTATUS) {
+               bool speed_100, duplex_full;
+               u32 flow_ctrl_config = 0;
+               u16 output_status = _sc92031_mii_read(port_base,
+                               MII_OutputStatus);
+               _sc92031_mii_scan(port_base);
+
+               speed_100 = output_status & 0x2;
+               duplex_full = output_status & 0x4;
+
+               /* Initial Tx/Rx configuration */
+               priv->rx_config = (0x40 << LowThresholdShift) | (0x1c0 << HighThresholdShift);
+               priv->tx_config = 0x48800000;
+
+               /* NOTE: vendor driver had dead code here to enable tx padding */
+
+               if (!speed_100)
+                       priv->tx_config |= 0x80000;
+
+               // configure rx mode
+               _sc92031_set_rx_config(dev);
+
+               if (duplex_full) {
+                       priv->rx_config |= RxFullDx;
+                       priv->tx_config |= TxFullDx;
+                       flow_ctrl_config = FlowCtrlFullDX | FlowCtrlEnb;
+               } else {
+                       priv->rx_config &= ~RxFullDx;
+                       priv->tx_config &= ~TxFullDx;
+               }
+
+               _sc92031_set_mar(dev);
+               _sc92031_set_rx_config(dev);
+               _sc92031_enable_tx_rx(dev);
+               iowrite32(flow_ctrl_config, port_base + FlowCtrlConfig);
+
+               netif_carrier_on(dev);
+
+               if (printk_ratelimit())
+                       printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n",
+                               dev->name,
+                               speed_100 ? "100" : "10",
+                               duplex_full ? "full" : "half");
+               return true;
+       } else {
+               _sc92031_mii_scan(port_base);
+
+               netif_carrier_off(dev);
+
+               _sc92031_disable_tx_rx(dev);
+
+               if (printk_ratelimit())
+                       printk(KERN_INFO "%s: link down\n", dev->name);
+               return false;
+       }
+}
+
+static void _sc92031_phy_reset(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+       u32 phy_ctrl;
+
+       phy_ctrl = ioread32(port_base + PhyCtrl);
+       phy_ctrl &= ~(PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10);
+       phy_ctrl |= PhyCtrlAne | PhyCtrlReset;
+
+       switch (media) {
+       default:
+       case AUTOSELECT:
+               phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10;
+               break;
+       case M10_HALF:
+               phy_ctrl |= PhyCtrlSpd10;
+               break;
+       case M10_FULL:
+               phy_ctrl |= PhyCtrlDux | PhyCtrlSpd10;
+               break;
+       case M100_HALF:
+               phy_ctrl |= PhyCtrlSpd100;
+               break;
+       case M100_FULL:
+               phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100;
+               break;
+       }
+
+       iowrite32(phy_ctrl, port_base + PhyCtrl);
+       mdelay(10);
+
+       phy_ctrl &= ~PhyCtrlReset;
+       iowrite32(phy_ctrl, port_base + PhyCtrl);
+       mdelay(1);
+
+       _sc92031_mii_write(port_base, MII_JAB,
+                       PHY_16_JAB_ENB | PHY_16_PORT_ENB);
+       _sc92031_mii_scan(port_base);
+
+       netif_carrier_off(dev);
+       netif_stop_queue(dev);
+}
+
+static void _sc92031_reset(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+
+       /* disable PM */
+       iowrite32(0, port_base + PMConfig);
+
+       /* soft reset the chip */
+       iowrite32(Cfg0_Reset, port_base + Config0);
+       mdelay(200);
+
+       iowrite32(0, port_base + Config0);
+       mdelay(10);
+
+       /* disable interrupts */
+       iowrite32(0, port_base + IntrMask);
+
+       /* clear multicast address */
+       iowrite32(0, port_base + MAR0);
+       iowrite32(0, port_base + MAR0 + 4);
+
+       /* init rx ring */
+       iowrite32(priv->rx_ring_dma_addr, port_base + RxbufAddr);
+       priv->rx_ring_tail = priv->rx_ring_dma_addr;
+
+       /* init tx ring */
+       _sc92031_tx_clear(dev);
+
+       /* clear old register values */
+       priv->intr_status = 0;
+       atomic_set(&priv->intr_mask, 0);
+       priv->rx_config = 0;
+       priv->tx_config = 0;
+       priv->mc_flags = 0;
+
+       /* configure rx buffer size */
+       /* NOTE: vendor driver had dead code here to enable early tx/rx */
+       iowrite32(Cfg1_Rcv64K, port_base + Config1);
+
+       _sc92031_phy_reset(dev);
+       _sc92031_check_media(dev);
+
+       /* calculate rx fifo overflow */
+       priv->rx_value = 0;
+
+       /* enable PM */
+       iowrite32(priv->pm_config, port_base + PMConfig);
+
+       /* clear intr register */
+       ioread32(port_base + IntrStatus);
+}
+
+static void _sc92031_tx_tasklet(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+
+       unsigned old_tx_tail;
+       unsigned entry;
+       u32 tx_status;
+
+       old_tx_tail = priv->tx_tail;
+       while (priv->tx_head - priv->tx_tail > 0) {
+               entry = priv->tx_tail % NUM_TX_DESC;
+               tx_status = ioread32(port_base + TxStatus0 + entry * 4);
+
+               if (!(tx_status & (TxStatOK | TxUnderrun | TxAborted)))
+                       break;
+
+               priv->tx_tail++;
+
+               if (tx_status & TxStatOK) {
+                       priv->stats.tx_bytes += tx_status & 0x1fff;
+                       priv->stats.tx_packets++;
+                       /* Note: TxCarrierLost is always asserted at 100mbps. */
+                       priv->stats.collisions += (tx_status >> 22) & 0xf;
+               }
+
+               if (tx_status & (TxOutOfWindow | TxAborted)) {
+                       priv->stats.tx_errors++;
+
+                       if (tx_status & TxAborted)
+                               priv->stats.tx_aborted_errors++;
+
+                       if (tx_status & TxCarrierLost)
+                               priv->stats.tx_carrier_errors++;
+
+                       if (tx_status & TxOutOfWindow)
+                               priv->stats.tx_window_errors++;
+               }
+
+               if (tx_status & TxUnderrun)
+                       priv->stats.tx_fifo_errors++;
+       }
+
+       if (priv->tx_tail != old_tx_tail)
+               if (netif_queue_stopped(dev))
+                       netif_wake_queue(dev);
+}
+
+static void _sc92031_rx_tasklet_error(u32 rx_status,
+               struct sc92031_priv *priv, unsigned rx_size)
+{
+       if(rx_size > (MAX_ETH_FRAME_SIZE + 4) || rx_size < 16) {
+               priv->stats.rx_errors++;
+               priv->stats.rx_length_errors++;
+       }
+
+       if (!(rx_status & RxStatesOK)) {
+               priv->stats.rx_errors++;
+
+               if (rx_status & (RxHugeFrame | RxSmallFrame))
+                       priv->stats.rx_length_errors++;
+
+               if (rx_status & RxBadAlign)
+                       priv->stats.rx_frame_errors++;
+
+               if (!(rx_status & RxCRCOK))
+                       priv->stats.rx_crc_errors++;
+       } else
+               priv->rx_loss++;
+}
+
+static void _sc92031_rx_tasklet(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+
+       dma_addr_t rx_ring_head;
+       unsigned rx_len;
+       unsigned rx_ring_offset;
+       void *rx_ring = priv->rx_ring;
+
+       rx_ring_head = ioread32(port_base + RxBufWPtr);
+       rmb();
+
+       /* rx_ring_head is only 17 bits in the RxBufWPtr register.
+        * we need to change it to 32 bits physical address
+        */
+       rx_ring_head &= (dma_addr_t)(RX_BUF_LEN - 1);
+       rx_ring_head |= priv->rx_ring_dma_addr & ~(dma_addr_t)(RX_BUF_LEN - 1);
+       if (rx_ring_head < priv->rx_ring_dma_addr)
+               rx_ring_head += RX_BUF_LEN;
+
+       if (rx_ring_head >= priv->rx_ring_tail)
+               rx_len = rx_ring_head - priv->rx_ring_tail;
+       else
+               rx_len = RX_BUF_LEN - (priv->rx_ring_tail - rx_ring_head);
+
+       if (!rx_len)
+               return;
+
+       if (unlikely(rx_len > RX_BUF_LEN)) {
+               if (printk_ratelimit())
+                       printk(KERN_ERR "%s: rx packets length > rx buffer\n",
+                                       dev->name);
+               return;
+       }
+
+       rx_ring_offset = (priv->rx_ring_tail - priv->rx_ring_dma_addr) % RX_BUF_LEN;
+
+       while (rx_len) {
+               u32 rx_status;
+               unsigned rx_size, rx_size_align, pkt_size;
+               struct sk_buff *skb;
+
+               rx_status = le32_to_cpup((__le32 *)(rx_ring + rx_ring_offset));
+               rmb();
+
+               rx_size = rx_status >> 20;
+               rx_size_align = (rx_size + 3) & ~3;     // for 4 bytes aligned
+               pkt_size = rx_size - 4; // Omit the four octet CRC from the length.
+
+               rx_ring_offset = (rx_ring_offset + 4) % RX_BUF_LEN;
+
+               if (unlikely(rx_status == 0
+                               || rx_size > (MAX_ETH_FRAME_SIZE + 4)
+                               || rx_size < 16
+                               || !(rx_status & RxStatesOK))) {
+                       _sc92031_rx_tasklet_error(rx_status, priv, rx_size);
+                       break;
+               }
+
+               if (unlikely(rx_size_align + 4 > rx_len)) {
+                       if (printk_ratelimit())
+                               printk(KERN_ERR "%s: rx_len is too small\n", dev->name);
+                       break;
+               }
+
+               rx_len -= rx_size_align + 4;
+
+               skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
+               if (unlikely(!skb)) {
+                       if (printk_ratelimit())
+                               printk(KERN_ERR "%s: Couldn't allocate a skb_buff for a packet of size %u\n",
+                                               dev->name, pkt_size);
+                       goto next;
+               }
+
+               skb_reserve(skb, NET_IP_ALIGN);
+
+               if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) {
+                       memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset),
+                               rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset);
+                       memcpy(skb_put(skb, pkt_size - (RX_BUF_LEN - rx_ring_offset)),
+                               rx_ring, pkt_size - (RX_BUF_LEN - rx_ring_offset));
+               } else {
+                       memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size);
+               }
+
+               skb->dev = dev;
+               skb->protocol = eth_type_trans(skb, dev);
+               dev->last_rx = jiffies;
+               netif_rx(skb);
+
+               priv->stats.rx_bytes += pkt_size;
+               priv->stats.rx_packets++;
+
+               if (rx_status & Rx_Multicast)
+                       priv->stats.multicast++;
+
+       next:
+               rx_ring_offset = (rx_ring_offset + rx_size_align) % RX_BUF_LEN;
+       }
+       mb();
+
+       priv->rx_ring_tail = rx_ring_head;
+       iowrite32(priv->rx_ring_tail, port_base + RxBufRPtr);
+}
+
+static void _sc92031_link_tasklet(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+
+       if (_sc92031_check_media(dev))
+               netif_wake_queue(dev);
+       else {
+               netif_stop_queue(dev);
+               priv->stats.tx_carrier_errors++;
+       }
+}
+
+static void sc92031_tasklet(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+       u32 intr_status, intr_mask;
+
+       intr_status = priv->intr_status;
+
+       spin_lock(&priv->lock);
+
+       if (unlikely(!netif_running(dev)))
+               goto out;
+
+       if (intr_status & TxOK)
+               _sc92031_tx_tasklet(dev);
+
+       if (intr_status & RxOK)
+               _sc92031_rx_tasklet(dev);
+
+       if (intr_status & RxOverflow)
+               priv->stats.rx_errors++;
+
+       if (intr_status & TimeOut) {
+               priv->stats.rx_errors++;
+               priv->stats.rx_length_errors++;
+       }
+
+       if (intr_status & (LinkFail | LinkOK))
+               _sc92031_link_tasklet(dev);
+
+out:
+       intr_mask = atomic_read(&priv->intr_mask);
+       rmb();
+
+       iowrite32(intr_mask, port_base + IntrMask);
+       mmiowb();
+
+       spin_unlock(&priv->lock);
+}
+
+static irqreturn_t sc92031_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+       u32 intr_status, intr_mask;
+
+       /* mask interrupts before clearing IntrStatus */
+       iowrite32(0, port_base + IntrMask);
+       _sc92031_dummy_read(port_base);
+
+       intr_status = ioread32(port_base + IntrStatus);
+       if (unlikely(intr_status == 0xffffffff))
+               return IRQ_NONE;        // hardware has gone missing
+
+       intr_status &= IntrBits;
+       if (!intr_status)
+               goto out_none;
+
+       priv->intr_status = intr_status;
+       tasklet_schedule(&priv->tasklet);
+
+       return IRQ_HANDLED;
+
+out_none:
+       intr_mask = atomic_read(&priv->intr_mask);
+       rmb();
+
+       iowrite32(intr_mask, port_base + IntrMask);
+       mmiowb();
+
+       return IRQ_NONE;
+}
+
+static struct net_device_stats *sc92031_get_stats(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+
+       // FIXME I do not understand what is this trying to do.
+       if (netif_running(dev)) {
+               int temp;
+
+               spin_lock_bh(&priv->lock);
+
+               /* Update the error count. */
+               temp = (ioread32(port_base + RxStatus0) >> 16) & 0xffff;
+
+               if (temp == 0xffff) {
+                       priv->rx_value += temp;
+                       priv->stats.rx_fifo_errors = priv->rx_value;
+               } else {
+                       priv->stats.rx_fifo_errors = temp + priv->rx_value;
+               }
+
+               spin_unlock_bh(&priv->lock);
+       }
+
+       return &priv->stats;
+}
+
+static int sc92031_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       int err = 0;
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+
+       unsigned len;
+       unsigned entry;
+       u32 tx_status;
+
+       if (unlikely(skb->len > TX_BUF_SIZE)) {
+               err = -EMSGSIZE;
+               priv->stats.tx_dropped++;
+               goto out;
+       }
+
+       spin_lock_bh(&priv->lock);
+
+       if (unlikely(!netif_carrier_ok(dev))) {
+               err = -ENOLINK;
+               priv->stats.tx_dropped++;
+               goto out_unlock;
+       }
+
+       BUG_ON(priv->tx_head - priv->tx_tail >= NUM_TX_DESC);
+
+       entry = priv->tx_head++ % NUM_TX_DESC;
+
+       skb_copy_and_csum_dev(skb, priv->tx_bufs + entry * TX_BUF_SIZE);
+
+       len = skb->len;
+       if (unlikely(len < ETH_ZLEN)) {
+               memset(priv->tx_bufs + entry * TX_BUF_SIZE + len,
+                               0, ETH_ZLEN - len);
+               len = ETH_ZLEN;
+       }
+
+       wmb();
+
+       if (len < 100)
+               tx_status = len;
+       else if (len < 300)
+               tx_status = 0x30000 | len;
+       else
+               tx_status = 0x50000 | len;
+
+       iowrite32(priv->tx_bufs_dma_addr + entry * TX_BUF_SIZE,
+                       port_base + TxAddr0 + entry * 4);
+       iowrite32(tx_status, port_base + TxStatus0 + entry * 4);
+       mmiowb();
+
+       dev->trans_start = jiffies;
+
+       if (priv->tx_head - priv->tx_tail >= NUM_TX_DESC)
+               netif_stop_queue(dev);
+
+out_unlock:
+       spin_unlock_bh(&priv->lock);
+
+out:
+       dev_kfree_skb(skb);
+
+       return err;
+}
+
+static int sc92031_open(struct net_device *dev)
+{
+       int err;
+       struct sc92031_priv *priv = netdev_priv(dev);
+       struct pci_dev *pdev = priv->pdev;
+
+       priv->rx_ring = pci_alloc_consistent(pdev, RX_BUF_LEN,
+                       &priv->rx_ring_dma_addr);
+       if (unlikely(!priv->rx_ring)) {
+               err = -ENOMEM;
+               goto out_alloc_rx_ring;
+       }
+
+       priv->tx_bufs = pci_alloc_consistent(pdev, TX_BUF_TOT_LEN,
+                       &priv->tx_bufs_dma_addr);
+       if (unlikely(!priv->tx_bufs)) {
+               err = -ENOMEM;
+               goto out_alloc_tx_bufs;
+       }
+       priv->tx_head = priv->tx_tail = 0;
+
+       err = request_irq(pdev->irq, sc92031_interrupt,
+                       SA_SHIRQ, dev->name, dev);
+       if (unlikely(err < 0))
+               goto out_request_irq;
+
+       priv->pm_config = 0;
+
+       /* Interrupts already disabled by sc92031_stop or sc92031_probe */
+       spin_lock(&priv->lock);
+
+       _sc92031_reset(dev);
+       mmiowb();
+
+       spin_unlock(&priv->lock);
+       sc92031_enable_interrupts(dev);
+
+       if (netif_carrier_ok(dev))
+               netif_start_queue(dev);
+       else
+               netif_tx_disable(dev);
+
+       return 0;
+
+out_request_irq:
+       pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs,
+                       priv->tx_bufs_dma_addr);
+out_alloc_tx_bufs:
+       pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring,
+                       priv->rx_ring_dma_addr);
+out_alloc_rx_ring:
+       return err;
+}
+
+static int sc92031_stop(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       struct pci_dev *pdev = priv->pdev;
+
+       netif_tx_disable(dev);
+
+       /* Disable interrupts, stop Tx and Rx. */
+       sc92031_disable_interrupts(dev);
+
+       spin_lock(&priv->lock);
+
+       _sc92031_disable_tx_rx(dev);
+       _sc92031_tx_clear(dev);
+       mmiowb();
+
+       spin_unlock(&priv->lock);
+
+       free_irq(pdev->irq, dev);
+       pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs,
+                       priv->tx_bufs_dma_addr);
+       pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring,
+                       priv->rx_ring_dma_addr);
+
+       return 0;
+}
+
+static void sc92031_set_multicast_list(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+
+       spin_lock_bh(&priv->lock);
+
+       _sc92031_set_mar(dev);
+       _sc92031_set_rx_config(dev);
+       mmiowb();
+
+       spin_unlock_bh(&priv->lock);
+}
+
+static void sc92031_tx_timeout(struct net_device *dev)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+
+       /* Disable interrupts by clearing the interrupt mask.*/
+       sc92031_disable_interrupts(dev);
+
+       spin_lock(&priv->lock);
+
+       priv->tx_timeouts++;
+
+       _sc92031_reset(dev);
+       mmiowb();
+
+       spin_unlock(&priv->lock);
+
+       /* enable interrupts */
+       sc92031_enable_interrupts(dev);
+
+       if (netif_carrier_ok(dev))
+               netif_wake_queue(dev);
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+static void sc92031_poll_controller(struct net_device *dev)
+{
+       disable_irq(dev->irq);
+       if (sc92031_interrupt(dev->irq, dev) != IRQ_NONE)
+               sc92031_tasklet((unsigned long)dev);
+       enable_irq(dev->irq);
+}
+#endif
+
+static int sc92031_ethtool_get_settings(struct net_device *dev,
+               struct ethtool_cmd *cmd)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+       u8 phy_address;
+       u32 phy_ctrl;
+       u16 output_status;
+
+       spin_lock_bh(&priv->lock);
+
+       phy_address = ioread32(port_base + Miicmd1) >> 27;
+       phy_ctrl = ioread32(port_base + PhyCtrl);
+
+       output_status = _sc92031_mii_read(port_base, MII_OutputStatus);
+       _sc92031_mii_scan(port_base);
+       mmiowb();
+
+       spin_unlock_bh(&priv->lock);
+
+       cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full
+                       | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full
+                       | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII;
+
+       cmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
+
+       if ((phy_ctrl & (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10))
+                       == (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10))
+               cmd->advertising |= ADVERTISED_Autoneg;
+
+       if ((phy_ctrl & PhyCtrlSpd10) == PhyCtrlSpd10)
+               cmd->advertising |= ADVERTISED_10baseT_Half;
+
+       if ((phy_ctrl & (PhyCtrlSpd10 | PhyCtrlDux))
+                       == (PhyCtrlSpd10 | PhyCtrlDux))
+               cmd->advertising |= ADVERTISED_10baseT_Full;
+
+       if ((phy_ctrl & PhyCtrlSpd100) == PhyCtrlSpd100)
+               cmd->advertising |= ADVERTISED_100baseT_Half;
+
+       if ((phy_ctrl & (PhyCtrlSpd100 | PhyCtrlDux))
+                       == (PhyCtrlSpd100 | PhyCtrlDux))
+               cmd->advertising |= ADVERTISED_100baseT_Full;
+
+       if (phy_ctrl & PhyCtrlAne)
+               cmd->advertising |= ADVERTISED_Autoneg;
+
+       cmd->speed = (output_status & 0x2) ? SPEED_100 : SPEED_10;
+       cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF;
+       cmd->port = PORT_MII;
+       cmd->phy_address = phy_address;
+       cmd->transceiver = XCVR_INTERNAL;
+       cmd->autoneg = (phy_ctrl & PhyCtrlAne) ? AUTONEG_ENABLE : AUTONEG_DISABLE;
+
+       return 0;
+}
+
+static int sc92031_ethtool_set_settings(struct net_device *dev,
+               struct ethtool_cmd *cmd)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+       u32 phy_ctrl;
+       u32 old_phy_ctrl;
+
+       if (!(cmd->speed == SPEED_10 || cmd->speed == SPEED_100))
+               return -EINVAL;
+       if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL))
+               return -EINVAL;
+       if (!(cmd->port == PORT_MII))
+               return -EINVAL;
+       if (!(cmd->phy_address == 0x1f))
+               return -EINVAL;
+       if (!(cmd->transceiver == XCVR_INTERNAL))
+               return -EINVAL;
+       if (!(cmd->autoneg == AUTONEG_DISABLE || cmd->autoneg == AUTONEG_ENABLE))
+               return -EINVAL;
+
+       if (cmd->autoneg == AUTONEG_ENABLE) {
+               if (!(cmd->advertising & (ADVERTISED_Autoneg
+                               | ADVERTISED_100baseT_Full
+                               | ADVERTISED_100baseT_Half
+                               | ADVERTISED_10baseT_Full
+                               | ADVERTISED_10baseT_Half)))
+                       return -EINVAL;
+
+               phy_ctrl = PhyCtrlAne;
+
+               // FIXME: I'm not sure what the original code was trying to do
+               if (cmd->advertising & ADVERTISED_Autoneg)
+                       phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10;
+               if (cmd->advertising & ADVERTISED_100baseT_Full)
+                       phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100;
+               if (cmd->advertising & ADVERTISED_100baseT_Half)
+                       phy_ctrl |= PhyCtrlSpd100;
+               if (cmd->advertising & ADVERTISED_10baseT_Full)
+                       phy_ctrl |= PhyCtrlSpd10 | PhyCtrlDux;
+               if (cmd->advertising & ADVERTISED_10baseT_Half)
+                       phy_ctrl |= PhyCtrlSpd10;
+       } else {
+               // FIXME: Whole branch guessed
+               phy_ctrl = 0;
+
+               if (cmd->speed == SPEED_10)
+                       phy_ctrl |= PhyCtrlSpd10;
+               else /* cmd->speed == SPEED_100 */
+                       phy_ctrl |= PhyCtrlSpd100;
+
+               if (cmd->duplex == DUPLEX_FULL)
+                       phy_ctrl |= PhyCtrlDux;
+       }
+
+       spin_lock_bh(&priv->lock);
+
+       old_phy_ctrl = ioread32(port_base + PhyCtrl);
+       phy_ctrl |= old_phy_ctrl & ~(PhyCtrlAne | PhyCtrlDux
+                       | PhyCtrlSpd100 | PhyCtrlSpd10);
+       if (phy_ctrl != old_phy_ctrl)
+               iowrite32(phy_ctrl, port_base + PhyCtrl);
+
+       spin_unlock_bh(&priv->lock);
+
+       return 0;
+}
+
+static void sc92031_ethtool_get_drvinfo(struct net_device *dev,
+               struct ethtool_drvinfo *drvinfo)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       struct pci_dev *pdev = priv->pdev;
+
+       strcpy(drvinfo->driver, SC92031_NAME);
+       strcpy(drvinfo->version, SC92031_VERSION);
+       strcpy(drvinfo->bus_info, pci_name(pdev));
+}
+
+static void sc92031_ethtool_get_wol(struct net_device *dev,
+               struct ethtool_wolinfo *wolinfo)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+       u32 pm_config;
+
+       spin_lock_bh(&priv->lock);
+       pm_config = ioread32(port_base + PMConfig);
+       spin_unlock_bh(&priv->lock);
+
+       // FIXME: Guessed
+       wolinfo->supported = WAKE_PHY | WAKE_MAGIC
+                       | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
+       wolinfo->wolopts = 0;
+
+       if (pm_config & PM_LinkUp)
+               wolinfo->wolopts |= WAKE_PHY;
+
+       if (pm_config & PM_Magic)
+               wolinfo->wolopts |= WAKE_MAGIC;
+
+       if (pm_config & PM_WakeUp)
+               // FIXME: Guessed
+               wolinfo->wolopts |= WAKE_UCAST | WAKE_MCAST | WAKE_BCAST;
+}
+
+static int sc92031_ethtool_set_wol(struct net_device *dev,
+               struct ethtool_wolinfo *wolinfo)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+       u32 pm_config;
+
+       spin_lock_bh(&priv->lock);
+
+       pm_config = ioread32(port_base + PMConfig)
+                       & ~(PM_LinkUp | PM_Magic | PM_WakeUp);
+
+       if (wolinfo->wolopts & WAKE_PHY)
+               pm_config |= PM_LinkUp;
+
+       if (wolinfo->wolopts & WAKE_MAGIC)
+               pm_config |= PM_Magic;
+
+       // FIXME: Guessed
+       if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST))
+               pm_config |= PM_WakeUp;
+
+       priv->pm_config = pm_config;
+       iowrite32(pm_config, port_base + PMConfig);
+       mmiowb();
+
+       spin_unlock_bh(&priv->lock);
+
+       return 0;
+}
+
+static int sc92031_ethtool_nway_reset(struct net_device *dev)
+{
+       int err = 0;
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem *port_base = priv->port_base;
+       u16 bmcr;
+
+       spin_lock_bh(&priv->lock);
+
+       bmcr = _sc92031_mii_read(port_base, MII_BMCR);
+       if (!(bmcr & BMCR_ANENABLE)) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       _sc92031_mii_write(port_base, MII_BMCR, bmcr | BMCR_ANRESTART);
+
+out:
+       _sc92031_mii_scan(port_base);
+       mmiowb();
+
+       spin_unlock_bh(&priv->lock);
+
+       return err;
+}
+
+static const char sc92031_ethtool_stats_strings[SILAN_STATS_NUM][ETH_GSTRING_LEN] = {
+       "tx_timeout",
+       "rx_loss",
+};
+
+static void sc92031_ethtool_get_strings(struct net_device *dev,
+               u32 stringset, u8 *data)
+{
+       if (stringset == ETH_SS_STATS)
+               memcpy(data, sc92031_ethtool_stats_strings,
+                               SILAN_STATS_NUM * ETH_GSTRING_LEN);
+}
+
+static int sc92031_ethtool_get_stats_count(struct net_device *dev)
+{
+       return SILAN_STATS_NUM;
+}
+
+static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev,
+               struct ethtool_stats *stats, u64 *data)
+{
+       struct sc92031_priv *priv = netdev_priv(dev);
+
+       spin_lock_bh(&priv->lock);
+       data[0] = priv->tx_timeouts;
+       data[1] = priv->rx_loss;
+       spin_unlock_bh(&priv->lock);
+}
+
+static struct ethtool_ops sc92031_ethtool_ops = {
+       .get_settings           = sc92031_ethtool_get_settings,
+       .set_settings           = sc92031_ethtool_set_settings,
+       .get_drvinfo            = sc92031_ethtool_get_drvinfo,
+       .get_wol                = sc92031_ethtool_get_wol,
+       .set_wol                = sc92031_ethtool_set_wol,
+       .nway_reset             = sc92031_ethtool_nway_reset,
+       .get_link               = ethtool_op_get_link,
+       .get_tx_csum            = ethtool_op_get_tx_csum,
+       .get_sg                 = ethtool_op_get_sg,
+       .get_tso                = ethtool_op_get_tso,
+       .get_strings            = sc92031_ethtool_get_strings,
+       .get_stats_count        = sc92031_ethtool_get_stats_count,
+       .get_ethtool_stats      = sc92031_ethtool_get_ethtool_stats,
+       .get_perm_addr          = ethtool_op_get_perm_addr,
+       .get_ufo                = ethtool_op_get_ufo,
+};
+
+static int __devinit sc92031_probe(struct pci_dev *pdev,
+               const struct pci_device_id *id)
+{
+       int err;
+       void __iomem* port_base;
+       struct net_device *dev;
+       struct sc92031_priv *priv;
+       u32 mac0, mac1;
+
+       err = pci_enable_device(pdev);
+       if (unlikely(err < 0))
+               goto out_enable_device;
+
+       pci_set_master(pdev);
+
+       err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+       if (unlikely(err < 0))
+               goto out_set_dma_mask;
+
+       err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+       if (unlikely(err < 0))
+               goto out_set_dma_mask;
+
+       err = pci_request_regions(pdev, SC92031_NAME);
+       if (unlikely(err < 0))
+               goto out_request_regions;
+
+       port_base = pci_iomap(pdev, SC92031_USE_BAR, 0);
+       if (unlikely(!port_base)) {
+               err = -EIO;
+               goto out_iomap;
+       }
+
+       dev = alloc_etherdev(sizeof(struct sc92031_priv));
+       if (unlikely(!dev)) {
+               err = -ENOMEM;
+               goto out_alloc_etherdev;
+       }
+
+       pci_set_drvdata(pdev, dev);
+
+#if SC92031_USE_BAR == 0
+       dev->mem_start = pci_resource_start(pdev, SC92031_USE_BAR);
+       dev->mem_end = pci_resource_end(pdev, SC92031_USE_BAR);
+#elif SC92031_USE_BAR == 1
+       dev->base_addr = pci_resource_start(pdev, SC92031_USE_BAR);
+#endif
+       dev->irq = pdev->irq;
+
+       /* faked with skb_copy_and_csum_dev */
+       dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
+
+       dev->get_stats          = sc92031_get_stats;
+       dev->ethtool_ops        = &sc92031_ethtool_ops;
+       dev->hard_start_xmit    = sc92031_start_xmit;
+       dev->watchdog_timeo     = TX_TIMEOUT;
+       dev->open               = sc92031_open;
+       dev->stop               = sc92031_stop;
+       dev->set_multicast_list = sc92031_set_multicast_list;
+       dev->tx_timeout         = sc92031_tx_timeout;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller    = sc92031_poll_controller;
+#endif
+
+       priv = netdev_priv(dev);
+       spin_lock_init(&priv->lock);
+       priv->port_base = port_base;
+       priv->pdev = pdev;
+       tasklet_init(&priv->tasklet, sc92031_tasklet, (unsigned long)dev);
+       /* Fudge tasklet count so the call to sc92031_enable_interrupts at
+        * sc92031_open will work correctly */
+       tasklet_disable_nosync(&priv->tasklet);
+
+       /* PCI PM Wakeup */
+       iowrite32((~PM_LongWF & ~PM_LWPTN) | PM_Enable, port_base + PMConfig);
+
+       mac0 = ioread32(port_base + MAC0);
+       mac1 = ioread32(port_base + MAC0 + 4);
+       dev->dev_addr[0] = dev->perm_addr[0] = mac0 >> 24;
+       dev->dev_addr[1] = dev->perm_addr[1] = mac0 >> 16;
+       dev->dev_addr[2] = dev->perm_addr[2] = mac0 >> 8;
+       dev->dev_addr[3] = dev->perm_addr[3] = mac0;
+       dev->dev_addr[4] = dev->perm_addr[4] = mac1 >> 8;
+       dev->dev_addr[5] = dev->perm_addr[5] = mac1;
+
+       err = register_netdev(dev);
+       if (err < 0)
+               goto out_register_netdev;
+
+       return 0;
+
+out_register_netdev:
+       free_netdev(dev);
+out_alloc_etherdev:
+       pci_iounmap(pdev, port_base);
+out_iomap:
+       pci_release_regions(pdev);
+out_request_regions:
+out_set_dma_mask:
+       pci_disable_device(pdev);
+out_enable_device:
+       return err;
+}
+
+static void __devexit sc92031_remove(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct sc92031_priv *priv = netdev_priv(dev);
+       void __iomem* port_base = priv->port_base;
+
+       unregister_netdev(dev);
+       free_netdev(dev);
+       pci_iounmap(pdev, port_base);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+}
+
+static int sc92031_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct sc92031_priv *priv = netdev_priv(dev);
+
+       pci_save_state(pdev);
+
+       if (!netif_running(dev))
+               goto out;
+
+       netif_device_detach(dev);
+
+       /* Disable interrupts, stop Tx and Rx. */
+       sc92031_disable_interrupts(dev);
+
+       spin_lock(&priv->lock);
+
+       _sc92031_disable_tx_rx(dev);
+       _sc92031_tx_clear(dev);
+       mmiowb();
+
+       spin_unlock(&priv->lock);
+
+out:
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+       return 0;
+}
+
+static int sc92031_resume(struct pci_dev *pdev)
+{
+       struct net_device *dev = pci_get_drvdata(pdev);
+       struct sc92031_priv *priv = netdev_priv(dev);
+
+       pci_restore_state(pdev);
+       pci_set_power_state(pdev, PCI_D0);
+
+       if (!netif_running(dev))
+               goto out;
+
+       /* Interrupts already disabled by sc92031_suspend */
+       spin_lock(&priv->lock);
+
+       _sc92031_reset(dev);
+       mmiowb();
+
+       spin_unlock(&priv->lock);
+       sc92031_enable_interrupts(dev);
+
+       netif_device_attach(dev);
+
+       if (netif_carrier_ok(dev))
+               netif_wake_queue(dev);
+       else
+               netif_tx_disable(dev);
+
+out:
+       return 0;
+}
+
+static struct pci_device_id sc92031_pci_device_id_table[] __devinitdata = {
+       { PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_SC92031) },
+       { PCI_DEVICE(PCI_VENDOR_ID_SILAN, PCI_DEVICE_ID_SILAN_8139D) },
+       { 0, }
+};
+MODULE_DEVICE_TABLE(pci, sc92031_pci_device_id_table);
+
+static struct pci_driver sc92031_pci_driver = {
+       .name           = SC92031_NAME,
+       .id_table       = sc92031_pci_device_id_table,
+       .probe          = sc92031_probe,
+       .remove         = __devexit_p(sc92031_remove),
+       .suspend        = sc92031_suspend,
+       .resume         = sc92031_resume,
+};
+
+static int __init sc92031_init(void)
+{
+       printk(KERN_INFO SC92031_DESCRIPTION " " SC92031_VERSION "\n");
+       return pci_register_driver(&sc92031_pci_driver);
+}
+
+static void __exit sc92031_exit(void)
+{
+       pci_unregister_driver(&sc92031_pci_driver);
+}
+
+module_init(sc92031_init);
+module_exit(sc92031_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Cesar Eduardo Barros <cesarb@cesarb.net>");
+MODULE_DESCRIPTION(SC92031_DESCRIPTION);
+MODULE_VERSION(SC92031_VERSION);
diff --git a/drivers/net/sk_mca.c b/drivers/net/sk_mca.c
deleted file mode 100644 (file)
index 96e06c5..0000000
+++ /dev/null
@@ -1,1216 +0,0 @@
-/*
-net-3-driver for the SKNET MCA-based cards
-
-This is an extension to the Linux operating system, and is covered by the
-same GNU General Public License that covers that work.
-
-Copyright 1999 by Alfred Arnold (alfred@ccac.rwth-aachen.de,
-                                 alfred.arnold@lancom.de)
-
-This driver is based both on the 3C523 driver and the SK_G16 driver.
-
-paper sources:
-  'PC Hardware: Aufbau, Funktionsweise, Programmierung' by
-  Hans-Peter Messmer for the basic Microchannel stuff
-
-  'Linux Geraetetreiber' by Allesandro Rubini, Kalle Dalheimer
-  for help on Ethernet driver programming
-
-  'Ethernet/IEEE 802.3 Family 1992 World Network Data Book/Handbook' by AMD
-  for documentation on the AM7990 LANCE
-
-  'SKNET Personal Technisches Manual', Version 1.2 by Schneider&Koch
-  for documentation on the Junior board
-
-  'SK-NET MC2+ Technical Manual", Version 1.1 by Schneider&Koch for
-  documentation on the MC2 bord
-
-  A big thank you to the S&K support for providing me so quickly with
-  documentation!
-
-  Also see http://www.syskonnect.com/
-
-  Missing things:
-
-  -> set debug level via ioctl instead of compile-time switches
-  -> I didn't follow the development of the 2.1.x kernels, so my
-     assumptions about which things changed with which kernel version
-     are probably nonsense
-
-History:
-  May 16th, 1999
-       startup
-  May 22st, 1999
-       added private structure, methods
-        begun building data structures in RAM
-  May 23nd, 1999
-       can receive frames, send frames
-  May 24th, 1999
-        modularized initialization of LANCE
-        loadable as module
-       still Tx problem :-(
-  May 26th, 1999
-       MC2 works
-       support for multiple devices
-       display media type for MC2+
-  May 28th, 1999
-       fixed problem in GetLANCE leaving interrupts turned off
-        increase TX queue to 4 packets to improve send performance
-  May 29th, 1999
-       a few corrections in statistics, caught rcvr overruns
-        reinitialization of LANCE/board in critical situations
-        MCA info implemented
-       implemented LANCE multicast filter
-  Jun 6th, 1999
-       additions for Linux 2.2
-  Dec 25th, 1999
-       unfortunately there seem to be newer MC2+ boards that react
-       on IRQ 3/5/9/10 instead of 3/5/10/11, so we have to autoprobe
-       in questionable cases...
-  Dec 28th, 1999
-       integrated patches from David Weinehall & Bill Wendling for 2.3
-       kernels (isa_...functions).  Things are defined in a way that
-        it still works with 2.0.x 8-)
-  Dec 30th, 1999
-       added handling of the remaining interrupt conditions.  That
-        should cure the spurious hangs.
-  Jan 30th, 2000
-       newer kernels automatically probe more than one board, so the
-       'startslot' as a variable is also needed here
-  June 1st, 2000
-       added changes for recent 2.3 kernels
-
- *************************************************************************/
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/time.h>
-#include <linux/mca-legacy.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/bitops.h>
-
-#include <asm/processor.h>
-#include <asm/io.h>
-
-#define _SK_MCA_DRIVER_
-#include "sk_mca.h"
-
-/* ------------------------------------------------------------------------
- * global static data - not more since we can handle multiple boards and
- * have to pack all state info into the device struct!
- * ------------------------------------------------------------------------ */
-
-static char *MediaNames[Media_Count] =
-    { "10Base2", "10BaseT", "10Base5", "Unknown" };
-
-static unsigned char poly[] =
-    { 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0,
-       1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0
-};
-
-/* ------------------------------------------------------------------------
- * private subfunctions
- * ------------------------------------------------------------------------ */
-
-/* dump parts of shared memory - only needed during debugging */
-
-#ifdef DEBUG
-static void dumpmem(struct net_device *dev, u32 start, u32 len)
-{
-       skmca_priv *priv = netdev_priv(dev);
-       int z;
-
-       for (z = 0; z < len; z++) {
-               if ((z & 15) == 0)
-                       printk("%04x:", z);
-               printk(" %02x", readb(priv->base + start + z));
-               if ((z & 15) == 15)
-                       printk("\n");
-       }
-}
-
-/* print exact time - ditto */
-
-static void PrTime(void)
-{
-       struct timeval tv;
-
-       do_gettimeofday(&tv);
-       printk("%9d:%06d: ", tv.tv_sec, tv.tv_usec);
-}
-#endif
-
-/* deduce resources out of POS registers */
-
-static void __init getaddrs(int slot, int junior, int *base, int *irq,
-                    skmca_medium * medium)
-{
-       u_char pos0, pos1, pos2;
-
-       if (junior) {
-               pos0 = mca_read_stored_pos(slot, 2);
-               *base = ((pos0 & 0x0e) << 13) + 0xc0000;
-               *irq = ((pos0 & 0x10) >> 4) + 10;
-               *medium = Media_Unknown;
-       } else {
-               /* reset POS 104 Bits 0+1 so the shared memory region goes to the
-                  configured area between 640K and 1M.  Afterwards, enable the MC2.
-                  I really don't know what rode SK to do this... */
-
-               mca_write_pos(slot, 4,
-                             mca_read_stored_pos(slot, 4) & 0xfc);
-               mca_write_pos(slot, 2,
-                             mca_read_stored_pos(slot, 2) | 0x01);
-
-               pos1 = mca_read_stored_pos(slot, 3);
-               pos2 = mca_read_stored_pos(slot, 4);
-               *base = ((pos1 & 0x07) << 14) + 0xc0000;
-               switch (pos2 & 0x0c) {
-               case 0:
-                       *irq = 3;
-                       break;
-               case 4:
-                       *irq = 5;
-                       break;
-               case 8:
-                       *irq = -10;
-                       break;
-               case 12:
-                       *irq = -11;
-                       break;
-               }
-               *medium = (pos2 >> 6) & 3;
-       }
-}
-
-/* check for both cards:
-   When the MC2 is turned off, it was configured for more than 15MB RAM,
-   is disabled and won't get detected using the standard probe.  We
-   therefore have to scan the slots manually :-( */
-
-static int __init dofind(int *junior, int firstslot)
-{
-       int slot;
-       unsigned int id;
-
-       for (slot = firstslot; slot < MCA_MAX_SLOT_NR; slot++) {
-               id = mca_read_stored_pos(slot, 0)
-                   + (((unsigned int) mca_read_stored_pos(slot, 1)) << 8);
-
-               *junior = 0;
-               if (id == SKNET_MCA_ID)
-                       return slot;
-               *junior = 1;
-               if (id == SKNET_JUNIOR_MCA_ID)
-                       return slot;
-       }
-       return MCA_NOTFOUND;
-}
-
-/* reset the whole board */
-
-static void ResetBoard(struct net_device *dev)
-{
-       skmca_priv *priv = netdev_priv(dev);
-
-       writeb(CTRL_RESET_ON, priv->ctrladdr);
-       udelay(10);
-       writeb(CTRL_RESET_OFF, priv->ctrladdr);
-}
-
-/* wait for LANCE interface to become not busy */
-
-static int WaitLANCE(struct net_device *dev)
-{
-       skmca_priv *priv = netdev_priv(dev);
-       int t = 0;
-
-       while ((readb(priv->ctrladdr) & STAT_IO_BUSY) ==
-              STAT_IO_BUSY) {
-               udelay(1);
-               if (++t > 1000) {
-                       printk("%s: LANCE access timeout", dev->name);
-                       return 0;
-               }
-       }
-
-       return 1;
-}
-
-/* set LANCE register - must be atomic */
-
-static void SetLANCE(struct net_device *dev, u16 addr, u16 value)
-{
-       skmca_priv *priv = netdev_priv(dev);
-       unsigned long flags;
-
-       /* disable interrupts */
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       /* wait until no transfer is pending */
-
-       WaitLANCE(dev);
-
-       /* transfer register address to RAP */
-
-       writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
-       writew(addr, priv->ioregaddr);
-       writeb(IOCMD_GO, priv->cmdaddr);
-       udelay(1);
-       WaitLANCE(dev);
-
-       /* transfer data to register */
-
-       writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_DATA, priv->ctrladdr);
-       writew(value, priv->ioregaddr);
-       writeb(IOCMD_GO, priv->cmdaddr);
-       udelay(1);
-       WaitLANCE(dev);
-
-       /* reenable interrupts */
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-/* get LANCE register */
-
-static u16 GetLANCE(struct net_device *dev, u16 addr)
-{
-       skmca_priv *priv = netdev_priv(dev);
-       unsigned long flags;
-       unsigned int res;
-
-       /* disable interrupts */
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       /* wait until no transfer is pending */
-
-       WaitLANCE(dev);
-
-       /* transfer register address to RAP */
-
-       writeb(CTRL_RESET_OFF | CTRL_RW_WRITE | CTRL_ADR_RAP, priv->ctrladdr);
-       writew(addr, priv->ioregaddr);
-       writeb(IOCMD_GO, priv->cmdaddr);
-       udelay(1);
-       WaitLANCE(dev);
-
-       /* transfer data from register */
-
-       writeb(CTRL_RESET_OFF | CTRL_RW_READ | CTRL_ADR_DATA, priv->ctrladdr);
-       writeb(IOCMD_GO, priv->cmdaddr);
-       udelay(1);
-       WaitLANCE(dev);
-       res = readw(priv->ioregaddr);
-
-       /* reenable interrupts */
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       return res;
-}
-
-/* build up descriptors in shared RAM */
-
-static void InitDscrs(struct net_device *dev)
-{
-       skmca_priv *priv = netdev_priv(dev);
-       u32 bufaddr;
-
-       /* Set up Tx descriptors. The board has only 16K RAM so bits 16..23
-          are always 0. */
-
-       bufaddr = RAM_DATABASE;
-       {
-               LANCE_TxDescr descr;
-               int z;
-
-               for (z = 0; z < TXCOUNT; z++) {
-                       descr.LowAddr = bufaddr;
-                       descr.Flags = 0;
-                       descr.Len = 0xf000;
-                       descr.Status = 0;
-                       memcpy_toio(priv->base + RAM_TXBASE +
-                                  (z * sizeof(LANCE_TxDescr)), &descr,
-                                  sizeof(LANCE_TxDescr));
-                       memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
-                       bufaddr += RAM_BUFSIZE;
-               }
-       }
-
-       /* do the same for the Rx descriptors */
-
-       {
-               LANCE_RxDescr descr;
-               int z;
-
-               for (z = 0; z < RXCOUNT; z++) {
-                       descr.LowAddr = bufaddr;
-                       descr.Flags = RXDSCR_FLAGS_OWN;
-                       descr.MaxLen = -RAM_BUFSIZE;
-                       descr.Len = 0;
-                       memcpy_toio(priv->base + RAM_RXBASE +
-                                  (z * sizeof(LANCE_RxDescr)), &descr,
-                                  sizeof(LANCE_RxDescr));
-                       memset_io(priv->base + bufaddr, 0, RAM_BUFSIZE);
-                       bufaddr += RAM_BUFSIZE;
-               }
-       }
-}
-
-/* calculate the hash bit position for a given multicast address
-   taken more or less directly from the AMD datasheet... */
-
-static void UpdateCRC(unsigned char *CRC, int bit)
-{
-       int j;
-
-       /* shift CRC one bit */
-
-       memmove(CRC + 1, CRC, 32 * sizeof(unsigned char));
-       CRC[0] = 0;
-
-       /* if bit XOR controlbit = 1, set CRC = CRC XOR polynomial */
-
-       if (bit ^ CRC[32])
-               for (j = 0; j < 32; j++)
-                       CRC[j] ^= poly[j];
-}
-
-static unsigned int GetHash(char *address)
-{
-       unsigned char CRC[33];
-       int i, byte, hashcode;
-
-       /* a multicast address has bit 0 in the first byte set */
-
-       if ((address[0] & 1) == 0)
-               return -1;
-
-       /* initialize CRC */
-
-       memset(CRC, 1, sizeof(CRC));
-
-       /* loop through address bits */
-
-       for (byte = 0; byte < 6; byte++)
-               for (i = 0; i < 8; i++)
-                       UpdateCRC(CRC, (address[byte] >> i) & 1);
-
-       /* hashcode is the 6 least significant bits of the CRC */
-
-       hashcode = 0;
-       for (i = 0; i < 6; i++)
-               hashcode = (hashcode << 1) + CRC[i];
-       return hashcode;
-}
-
-/* feed ready-built initialization block into LANCE */
-
-static void InitLANCE(struct net_device *dev)
-{
-       skmca_priv *priv = netdev_priv(dev);
-
-       /* build up descriptors. */
-
-       InitDscrs(dev);
-
-       /* next RX descriptor to be read is the first one.  Since the LANCE
-          will start from the beginning after initialization, we have to
-          reset out pointers too. */
-
-       priv->nextrx = 0;
-
-       /* no TX descriptors active */
-
-       priv->nexttxput = priv->nexttxdone = priv->txbusy = 0;
-
-       /* set up the LANCE bus control register - constant for SKnet boards */
-
-       SetLANCE(dev, LANCE_CSR3,
-                CSR3_BSWAP_OFF | CSR3_ALE_LOW | CSR3_BCON_HOLD);
-
-       /* write address of initialization block into LANCE */
-
-       SetLANCE(dev, LANCE_CSR1, RAM_INITBASE & 0xffff);
-       SetLANCE(dev, LANCE_CSR2, (RAM_INITBASE >> 16) & 0xff);
-
-       /* we don't get ready until the LANCE has read the init block */
-
-       netif_stop_queue(dev);
-
-       /* let LANCE read the initialization block.  LANCE is ready
-          when we receive the corresponding interrupt. */
-
-       SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_INIT);
-}
-
-/* stop the LANCE so we can reinitialize it */
-
-static void StopLANCE(struct net_device *dev)
-{
-       /* can't take frames any more */
-
-       netif_stop_queue(dev);
-
-       /* disable interrupts, stop it */
-
-       SetLANCE(dev, LANCE_CSR0, CSR0_STOP);
-}
-
-/* initialize card and LANCE for proper operation */
-
-static void InitBoard(struct net_device *dev)
-{
-       skmca_priv *priv = netdev_priv(dev);
-       LANCE_InitBlock block;
-
-       /* Lay out the shared RAM - first we create the init block for the LANCE.
-          We do not overwrite it later because we need it again when we switch
-          promiscous mode on/off. */
-
-       block.Mode = 0;
-       if (dev->flags & IFF_PROMISC)
-               block.Mode |= LANCE_INIT_PROM;
-       memcpy(block.PAdr, dev->dev_addr, 6);
-       memset(block.LAdrF, 0, sizeof(block.LAdrF));
-       block.RdrP = (RAM_RXBASE & 0xffffff) | (LRXCOUNT << 29);
-       block.TdrP = (RAM_TXBASE & 0xffffff) | (LTXCOUNT << 29);
-
-       memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
-
-       /* initialize LANCE. Implicitly sets up other structures in RAM. */
-
-       InitLANCE(dev);
-}
-
-/* deinitialize card and LANCE */
-
-static void DeinitBoard(struct net_device *dev)
-{
-       /* stop LANCE */
-
-       StopLANCE(dev);
-
-       /* reset board */
-
-       ResetBoard(dev);
-}
-
-/* probe for device's irq */
-
-static int __init ProbeIRQ(struct net_device *dev)
-{
-       unsigned long imaskval, njiffies, irq;
-       u16 csr0val;
-
-       /* enable all interrupts */
-
-       imaskval = probe_irq_on();
-
-       /* initialize the board. Wait for interrupt 'Initialization done'. */
-
-       ResetBoard(dev);
-       InitBoard(dev);
-
-       njiffies = jiffies + HZ;
-       do {
-               csr0val = GetLANCE(dev, LANCE_CSR0);
-       }
-       while (((csr0val & CSR0_IDON) == 0) && (jiffies != njiffies));
-
-       /* turn of interrupts again */
-
-       irq = probe_irq_off(imaskval);
-
-       /* if we found something, ack the interrupt */
-
-       if (irq)
-               SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_IDON);
-
-       /* back to idle state */
-
-       DeinitBoard(dev);
-
-       return irq;
-}
-
-/* ------------------------------------------------------------------------
- * interrupt handler(s)
- * ------------------------------------------------------------------------ */
-
-/* LANCE has read initialization block -> start it */
-
-static u16 irqstart_handler(struct net_device *dev, u16 oldcsr0)
-{
-       /* now we're ready to transmit */
-
-       netif_wake_queue(dev);
-
-       /* reset IDON bit, start LANCE */
-
-       SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_IDON | CSR0_STRT);
-       return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* did we lose blocks due to a FIFO overrun ? */
-
-static u16 irqmiss_handler(struct net_device *dev, u16 oldcsr0)
-{
-       skmca_priv *priv = netdev_priv(dev);
-
-       /* update statistics */
-
-       priv->stat.rx_fifo_errors++;
-
-       /* reset MISS bit */
-
-       SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_MISS);
-       return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* receive interrupt */
-
-static u16 irqrx_handler(struct net_device *dev, u16 oldcsr0)
-{
-       skmca_priv *priv = netdev_priv(dev);
-       LANCE_RxDescr descr;
-       unsigned int descraddr;
-
-       /* run through queue until we reach a descriptor we do not own */
-
-       descraddr = RAM_RXBASE + (priv->nextrx * sizeof(LANCE_RxDescr));
-       while (1) {
-               /* read descriptor */
-               memcpy_fromio(&descr, priv->base + descraddr,
-                            sizeof(LANCE_RxDescr));
-
-               /* if we reach a descriptor we do not own, we're done */
-               if ((descr.Flags & RXDSCR_FLAGS_OWN) != 0)
-                       break;
-
-#ifdef DEBUG
-               PrTime();
-               printk("Receive packet on descr %d len %d\n", priv->nextrx,
-                      descr.Len);
-#endif
-
-               /* erroneous packet ? */
-               if ((descr.Flags & RXDSCR_FLAGS_ERR) != 0) {
-                       priv->stat.rx_errors++;
-                       if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
-                               priv->stat.rx_crc_errors++;
-                       else if ((descr.Flags & RXDSCR_FLAGS_CRC) != 0)
-                               priv->stat.rx_frame_errors++;
-                       else if ((descr.Flags & RXDSCR_FLAGS_OFLO) != 0)
-                               priv->stat.rx_fifo_errors++;
-               }
-
-               /* good packet ? */
-               else {
-                       struct sk_buff *skb;
-
-                       skb = dev_alloc_skb(descr.Len + 2);
-                       if (skb == NULL)
-                               priv->stat.rx_dropped++;
-                       else {
-                               memcpy_fromio(skb_put(skb, descr.Len),
-                                            priv->base +
-                                            descr.LowAddr, descr.Len);
-                               skb->dev = dev;
-                               skb->protocol = eth_type_trans(skb, dev);
-                               skb->ip_summed = CHECKSUM_NONE;
-                               priv->stat.rx_packets++;
-                               priv->stat.rx_bytes += descr.Len;
-                               netif_rx(skb);
-                               dev->last_rx = jiffies;
-                       }
-               }
-
-               /* give descriptor back to LANCE */
-               descr.Len = 0;
-               descr.Flags |= RXDSCR_FLAGS_OWN;
-
-               /* update descriptor in shared RAM */
-               memcpy_toio(priv->base + descraddr, &descr,
-                          sizeof(LANCE_RxDescr));
-
-               /* go to next descriptor */
-               priv->nextrx++;
-               descraddr += sizeof(LANCE_RxDescr);
-               if (priv->nextrx >= RXCOUNT) {
-                       priv->nextrx = 0;
-                       descraddr = RAM_RXBASE;
-               }
-       }
-
-       /* reset RINT bit */
-
-       SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_RINT);
-       return GetLANCE(dev, LANCE_CSR0);
-}
-
-/* transmit interrupt */
-
-static u16 irqtx_handler(struct net_device *dev, u16 oldcsr0)
-{
-       skmca_priv *priv = netdev_priv(dev);
-       LANCE_TxDescr descr;
-       unsigned int descraddr;
-
-       /* check descriptors at most until no busy one is left */
-
-       descraddr =
-           RAM_TXBASE + (priv->nexttxdone * sizeof(LANCE_TxDescr));
-       while (priv->txbusy > 0) {
-               /* read descriptor */
-               memcpy_fromio(&descr, priv->base + descraddr,
-                            sizeof(LANCE_TxDescr));
-
-               /* if the LANCE still owns this one, we've worked out all sent packets */
-               if ((descr.Flags & TXDSCR_FLAGS_OWN) != 0)
-                       break;
-
-#ifdef DEBUG
-               PrTime();
-               printk("Send packet done on descr %d\n", priv->nexttxdone);
-#endif
-
-               /* update statistics */
-               if ((descr.Flags & TXDSCR_FLAGS_ERR) == 0) {
-                       priv->stat.tx_packets++;
-                       priv->stat.tx_bytes++;
-               } else {
-                       priv->stat.tx_errors++;
-                       if ((descr.Status & TXDSCR_STATUS_UFLO) != 0) {
-                               priv->stat.tx_fifo_errors++;
-                               InitLANCE(dev);
-                       }
-                               else
-                           if ((descr.Status & TXDSCR_STATUS_LCOL) !=
-                               0) priv->stat.tx_window_errors++;
-                       else if ((descr.Status & TXDSCR_STATUS_LCAR) != 0)
-                               priv->stat.tx_carrier_errors++;
-                       else if ((descr.Status & TXDSCR_STATUS_RTRY) != 0)
-                               priv->stat.tx_aborted_errors++;
-               }
-
-               /* go to next descriptor */
-               priv->nexttxdone++;
-               descraddr += sizeof(LANCE_TxDescr);
-               if (priv->nexttxdone >= TXCOUNT) {
-                       priv->nexttxdone = 0;
-                       descraddr = RAM_TXBASE;
-               }
-               priv->txbusy--;
-       }
-
-       /* reset TX interrupt bit */
-
-       SetLANCE(dev, LANCE_CSR0, oldcsr0 | CSR0_TINT);
-       oldcsr0 = GetLANCE(dev, LANCE_CSR0);
-
-       /* at least one descriptor is freed.  Therefore we can accept
-          a new one */
-       /* inform upper layers we're in business again */
-
-       netif_wake_queue(dev);
-
-       return oldcsr0;
-}
-
-/* general interrupt entry */
-
-static irqreturn_t irq_handler(int irq, void *device)
-{
-       struct net_device *dev = (struct net_device *) device;
-       u16 csr0val;
-
-       /* read CSR0 to get interrupt cause */
-
-       csr0val = GetLANCE(dev, LANCE_CSR0);
-
-       /* in case we're not meant... */
-
-       if ((csr0val & CSR0_INTR) == 0)
-               return IRQ_NONE;
-
-#if 0
-       set_bit(LINK_STATE_RXSEM, &dev->state);
-#endif
-
-       /* loop through the interrupt bits until everything is clear */
-
-       do {
-               if ((csr0val & CSR0_IDON) != 0)
-                       csr0val = irqstart_handler(dev, csr0val);
-               if ((csr0val & CSR0_RINT) != 0)
-                       csr0val = irqrx_handler(dev, csr0val);
-               if ((csr0val & CSR0_MISS) != 0)
-                       csr0val = irqmiss_handler(dev, csr0val);
-               if ((csr0val & CSR0_TINT) != 0)
-                       csr0val = irqtx_handler(dev, csr0val);
-               if ((csr0val & CSR0_MERR) != 0) {
-                       SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_MERR);
-                       csr0val = GetLANCE(dev, LANCE_CSR0);
-               }
-               if ((csr0val & CSR0_BABL) != 0) {
-                       SetLANCE(dev, LANCE_CSR0, csr0val | CSR0_BABL);
-                       csr0val = GetLANCE(dev, LANCE_CSR0);
-               }
-       }
-       while ((csr0val & CSR0_INTR) != 0);
-
-#if 0
-       clear_bit(LINK_STATE_RXSEM, &dev->state);
-#endif
-       return IRQ_HANDLED;
-}
-
-/* ------------------------------------------------------------------------
- * driver methods
- * ------------------------------------------------------------------------ */
-
-/* MCA info */
-
-static int skmca_getinfo(char *buf, int slot, void *d)
-{
-       int len = 0, i;
-       struct net_device *dev = (struct net_device *) d;
-       skmca_priv *priv;
-
-       /* can't say anything about an uninitialized device... */
-
-       if (dev == NULL)
-               return len;
-       priv = netdev_priv(dev);
-
-       /* print info */
-
-       len += sprintf(buf + len, "IRQ: %d\n", priv->realirq);
-       len += sprintf(buf + len, "Memory: %#lx-%#lx\n", dev->mem_start,
-                      dev->mem_end - 1);
-       len +=
-           sprintf(buf + len, "Transceiver: %s\n",
-                   MediaNames[priv->medium]);
-       len += sprintf(buf + len, "Device: %s\n", dev->name);
-       len += sprintf(buf + len, "MAC address:");
-       for (i = 0; i < 6; i++)
-               len += sprintf(buf + len, " %02x", dev->dev_addr[i]);
-       buf[len++] = '\n';
-       buf[len] = 0;
-
-       return len;
-}
-
-/* open driver.  Means also initialization and start of LANCE */
-
-static int skmca_open(struct net_device *dev)
-{
-       int result;
-       skmca_priv *priv = netdev_priv(dev);
-
-       /* register resources - only necessary for IRQ */
-       result =
-           request_irq(priv->realirq, irq_handler,
-                       IRQF_SHARED | IRQF_SAMPLE_RANDOM, "sk_mca", dev);
-       if (result != 0) {
-               printk("%s: failed to register irq %d\n", dev->name,
-                      dev->irq);
-               return result;
-       }
-       dev->irq = priv->realirq;
-
-       /* set up the card and LANCE */
-
-       InitBoard(dev);
-
-       /* set up flags */
-
-       netif_start_queue(dev);
-
-       return 0;
-}
-
-/* close driver.  Shut down board and free allocated resources */
-
-static int skmca_close(struct net_device *dev)
-{
-       /* turn off board */
-       DeinitBoard(dev);
-
-       /* release resources */
-       if (dev->irq != 0)
-               free_irq(dev->irq, dev);
-       dev->irq = 0;
-
-       return 0;
-}
-
-/* transmit a block. */
-
-static int skmca_tx(struct sk_buff *skb, struct net_device *dev)
-{
-       skmca_priv *priv = netdev_priv(dev);
-       LANCE_TxDescr descr;
-       unsigned int address;
-       int tmplen, retval = 0;
-       unsigned long flags;
-
-       /* if we get called with a NULL descriptor, the Ethernet layer thinks
-          our card is stuck an we should reset it.  We'll do this completely: */
-
-       if (skb == NULL) {
-               DeinitBoard(dev);
-               InitBoard(dev);
-               return 0;       /* don't try to free the block here ;-) */
-       }
-
-       /* is there space in the Tx queue ? If no, the upper layer gave us a
-          packet in spite of us not being ready and is really in trouble.
-          We'll do the dropping for him: */
-       if (priv->txbusy >= TXCOUNT) {
-               priv->stat.tx_dropped++;
-               retval = -EIO;
-               goto tx_done;
-       }
-
-       /* get TX descriptor */
-       address = RAM_TXBASE + (priv->nexttxput * sizeof(LANCE_TxDescr));
-       memcpy_fromio(&descr, priv->base + address, sizeof(LANCE_TxDescr));
-
-       /* enter packet length as 2s complement - assure minimum length */
-       tmplen = skb->len;
-       if (tmplen < 60)
-               tmplen = 60;
-       descr.Len = 65536 - tmplen;
-
-       /* copy filler into RAM - in case we're filling up...
-          we're filling a bit more than necessary, but that doesn't harm
-          since the buffer is far larger... */
-       if (tmplen > skb->len) {
-               char *fill = "NetBSD is a nice OS too! ";
-               unsigned int destoffs = 0, l = strlen(fill);
-
-               while (destoffs < tmplen) {
-                       memcpy_toio(priv->base + descr.LowAddr +
-                                  destoffs, fill, l);
-                       destoffs += l;
-               }
-       }
-
-       /* do the real data copying */
-       memcpy_toio(priv->base + descr.LowAddr, skb->data, skb->len);
-
-       /* hand descriptor over to LANCE - this is the first and last chunk */
-       descr.Flags =
-           TXDSCR_FLAGS_OWN | TXDSCR_FLAGS_STP | TXDSCR_FLAGS_ENP;
-
-#ifdef DEBUG
-       PrTime();
-       printk("Send packet on descr %d len %d\n", priv->nexttxput,
-              skb->len);
-#endif
-
-       /* one more descriptor busy */
-
-       spin_lock_irqsave(&priv->lock, flags);
-
-       priv->nexttxput++;
-       if (priv->nexttxput >= TXCOUNT)
-               priv->nexttxput = 0;
-       priv->txbusy++;
-
-       /* are we saturated ? */
-
-       if (priv->txbusy >= TXCOUNT)
-               netif_stop_queue(dev);
-
-       /* write descriptor back to RAM */
-       memcpy_toio(priv->base + address, &descr, sizeof(LANCE_TxDescr));
-
-       /* if no descriptors were active, give the LANCE a hint to read it
-          immediately */
-
-       if (priv->txbusy == 0)
-               SetLANCE(dev, LANCE_CSR0, CSR0_INEA | CSR0_TDMD);
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-      tx_done:
-
-       dev_kfree_skb(skb);
-
-       return retval;
-}
-
-/* return pointer to Ethernet statistics */
-
-static struct net_device_stats *skmca_stats(struct net_device *dev)
-{
-       skmca_priv *priv = netdev_priv(dev);
-
-       return &(priv->stat);
-}
-
-/* switch receiver mode.  We use the LANCE's multicast filter to prefilter
-   multicast addresses. */
-
-static void skmca_set_multicast_list(struct net_device *dev)
-{
-       skmca_priv *priv = netdev_priv(dev);
-       LANCE_InitBlock block;
-
-       /* first stop the LANCE... */
-       StopLANCE(dev);
-
-       /* ...then modify the initialization block... */
-       memcpy_fromio(&block, priv->base + RAM_INITBASE, sizeof(block));
-       if (dev->flags & IFF_PROMISC)
-               block.Mode |= LANCE_INIT_PROM;
-       else
-               block.Mode &= ~LANCE_INIT_PROM;
-
-       if (dev->flags & IFF_ALLMULTI) {        /* get all multicasts */
-               memset(block.LAdrF, 0xff, sizeof(block.LAdrF));
-       } else {                /* get selected/no multicasts */
-
-               struct dev_mc_list *mptr;
-               int code;
-
-               memset(block.LAdrF, 0, sizeof(block.LAdrF));
-               for (mptr = dev->mc_list; mptr != NULL; mptr = mptr->next) {
-                       code = GetHash(mptr->dmi_addr);
-                       block.LAdrF[(code >> 3) & 7] |= 1 << (code & 7);
-               }
-       }
-
-       memcpy_toio(priv->base + RAM_INITBASE, &block, sizeof(block));
-
-       /* ...then reinit LANCE with the correct flags */
-       InitLANCE(dev);
-}
-
-/* ------------------------------------------------------------------------
- * hardware check
- * ------------------------------------------------------------------------ */
-
-static int startslot;          /* counts through slots when probing multiple devices */
-
-static void cleanup_card(struct net_device *dev)
-{
-       skmca_priv *priv = netdev_priv(dev);
-       DeinitBoard(dev);
-       if (dev->irq != 0)
-               free_irq(dev->irq, dev);
-       iounmap(priv->base);
-       mca_mark_as_unused(priv->slot);
-       mca_set_adapter_procfn(priv->slot, NULL, NULL);
-}
-
-struct net_device * __init skmca_probe(int unit)
-{
-       struct net_device *dev;
-       int force_detect = 0;
-       int junior, slot, i;
-       int base = 0, irq = 0;
-       skmca_priv *priv;
-       skmca_medium medium;
-       int err;
-
-       /* can't work without an MCA bus ;-) */
-
-       if (MCA_bus == 0)
-               return ERR_PTR(-ENODEV);
-
-       dev = alloc_etherdev(sizeof(skmca_priv));
-       if (!dev)
-               return ERR_PTR(-ENOMEM);
-
-       if (unit >= 0) {
-               sprintf(dev->name, "eth%d", unit);
-               netdev_boot_setup_check(dev);
-       }
-
-       SET_MODULE_OWNER(dev);
-
-       /* start address of 1 --> forced detection */
-
-       if (dev->mem_start == 1)
-               force_detect = 1;
-
-       /* search through slots */
-
-       base = dev->mem_start;
-       irq = dev->base_addr;
-       for (slot = startslot; (slot = dofind(&junior, slot)) != -1; slot++) {
-               /* deduce card addresses */
-
-               getaddrs(slot, junior, &base, &irq, &medium);
-
-               /* slot already in use ? */
-
-               if (mca_is_adapter_used(slot))
-                       continue;
-
-               /* were we looking for something different ? */
-
-               if (dev->irq && dev->irq != irq)
-                       continue;
-               if (dev->mem_start && dev->mem_start != base)
-                       continue;
-
-               /* found something that matches */
-
-               break;
-       }
-
-       /* nothing found ? */
-
-       if (slot == -1) {
-               free_netdev(dev);
-               return (base || irq) ? ERR_PTR(-ENXIO) : ERR_PTR(-ENODEV);
-       }
-
-       /* make procfs entries */
-
-       if (junior)
-               mca_set_adapter_name(slot,
-                                    "SKNET junior MC2 Ethernet Adapter");
-       else
-               mca_set_adapter_name(slot, "SKNET MC2+ Ethernet Adapter");
-       mca_set_adapter_procfn(slot, (MCA_ProcFn) skmca_getinfo, dev);
-
-       mca_mark_as_used(slot);
-
-       /* announce success */
-       printk("%s: SKNet %s adapter found in slot %d\n", dev->name,
-              junior ? "Junior MC2" : "MC2+", slot + 1);
-
-       priv = netdev_priv(dev);
-       priv->base = ioremap(base, 0x4000);
-       if (!priv->base) {
-               mca_set_adapter_procfn(slot, NULL, NULL);
-               mca_mark_as_unused(slot);
-               free_netdev(dev);
-               return ERR_PTR(-ENOMEM);
-       }
-
-       priv->slot = slot;
-       priv->macbase = priv->base + 0x3fc0;
-       priv->ioregaddr = priv->base + 0x3ff0;
-       priv->ctrladdr = priv->base + 0x3ff2;
-       priv->cmdaddr = priv->base + 0x3ff3;
-       priv->medium = medium;
-       memset(&priv->stat, 0, sizeof(struct net_device_stats));
-       spin_lock_init(&priv->lock);
-
-       /* set base + irq for this device (irq not allocated so far) */
-       dev->irq = 0;
-       dev->mem_start = base;
-       dev->mem_end = base + 0x4000;
-
-       /* autoprobe ? */
-       if (irq < 0) {
-               int nirq;
-
-               printk
-                   ("%s: ambigous POS bit combination, must probe for IRQ...\n",
-                    dev->name);
-               nirq = ProbeIRQ(dev);
-               if (nirq <= 0)
-                       printk("%s: IRQ probe failed, assuming IRQ %d",
-                              dev->name, priv->realirq = -irq);
-               else
-                       priv->realirq = nirq;
-       } else
-               priv->realirq = irq;
-
-       /* set methods */
-       dev->open = skmca_open;
-       dev->stop = skmca_close;
-       dev->hard_start_xmit = skmca_tx;
-       dev->do_ioctl = NULL;
-       dev->get_stats = skmca_stats;
-       dev->set_multicast_list = skmca_set_multicast_list;
-       dev->flags |= IFF_MULTICAST;
-
-       /* copy out MAC address */
-       for (i = 0; i < 6; i++)
-               dev->dev_addr[i] = readb(priv->macbase + (i << 1));
-
-       /* print config */
-       printk("%s: IRQ %d, memory %#lx-%#lx, "
-              "MAC address %02x:%02x:%02x:%02x:%02x:%02x.\n",
-              dev->name, priv->realirq, dev->mem_start, dev->mem_end - 1,
-              dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
-              dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
-       printk("%s: %s medium\n", dev->name, MediaNames[priv->medium]);
-
-       /* reset board */
-
-       ResetBoard(dev);
-
-       startslot = slot + 1;
-
-       err = register_netdev(dev);
-       if (err) {
-               cleanup_card(dev);
-               free_netdev(dev);
-               dev = ERR_PTR(err);
-       }
-       return dev;
-}
-
-/* ------------------------------------------------------------------------
- * modularization support
- * ------------------------------------------------------------------------ */
-
-#ifdef MODULE
-MODULE_LICENSE("GPL");
-
-#define DEVMAX 5
-
-static struct net_device *moddevs[DEVMAX];
-
-int init_module(void)
-{
-       int z;
-
-       startslot = 0;
-       for (z = 0; z < DEVMAX; z++) {
-               struct net_device *dev = skmca_probe(-1);
-               if (IS_ERR(dev))
-                       break;
-               moddevs[z] = dev;
-       }
-       if (!z)
-               return -EIO;
-       return 0;
-}
-
-void cleanup_module(void)
-{
-       int z;
-
-       for (z = 0; z < DEVMAX; z++) {
-               struct net_device *dev = moddevs[z];
-               if (dev) {
-                       unregister_netdev(dev);
-                       cleanup_card(dev);
-                       free_netdev(dev);
-               }
-       }
-}
-#endif                         /* MODULE */
diff --git a/drivers/net/sk_mca.h b/drivers/net/sk_mca.h
deleted file mode 100644 (file)
index 0dae056..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-#ifndef _SK_MCA_INCLUDE_
-#define _SK_MCA_INCLUDE_
-
-#ifdef _SK_MCA_DRIVER_
-
-/* Adapter ID's */
-#define SKNET_MCA_ID 0x6afd
-#define SKNET_JUNIOR_MCA_ID 0x6be9
-
-/* media enumeration - defined in a way that it fits onto the MC2+'s
-   POS registers... */
-
-typedef enum { Media_10Base2, Media_10BaseT,
-       Media_10Base5, Media_Unknown, Media_Count
-} skmca_medium;
-
-/* private structure */
-typedef struct {
-       unsigned int slot;      /* MCA-Slot-#                       */
-       void __iomem *base;
-       void __iomem *macbase;  /* base address of MAC address PROM */
-       void __iomem *ioregaddr;/* address of I/O-register (Lo)     */
-       void __iomem *ctrladdr; /* address of control/stat register */
-       void __iomem *cmdaddr;  /* address of I/O-command register  */
-       int nextrx;             /* index of next RX descriptor to
-                                  be read                          */
-       int nexttxput;          /* index of next free TX descriptor */
-       int nexttxdone;         /* index of next TX descriptor to
-                                  be finished                      */
-       int txbusy;             /* # of busy TX descriptors         */
-       struct net_device_stats stat;   /* packet statistics            */
-       int realirq;            /* memorizes actual IRQ, even when
-                                  currently not allocated          */
-       skmca_medium medium;    /* physical cannector               */
-       spinlock_t lock;
-} skmca_priv;
-
-/* card registers: control/status register bits */
-
-#define CTRL_ADR_DATA      0   /* Bit 0 = 0 ->access data register  */
-#define CTRL_ADR_RAP       1   /* Bit 0 = 1 ->access RAP register   */
-#define CTRL_RW_WRITE      0   /* Bit 1 = 0 ->write register        */
-#define CTRL_RW_READ       2   /* Bit 1 = 1 ->read register         */
-#define CTRL_RESET_ON      0   /* Bit 3 = 0 ->reset board           */
-#define CTRL_RESET_OFF     8   /* Bit 3 = 1 ->no reset of board     */
-
-#define STAT_ADR_DATA      0   /* Bit 0 of ctrl register read back  */
-#define STAT_ADR_RAP       1
-#define STAT_RW_WRITE      0   /* Bit 1 of ctrl register read back  */
-#define STAT_RW_READ       2
-#define STAT_RESET_ON      0   /* Bit 3 of ctrl register read back  */
-#define STAT_RESET_OFF     8
-#define STAT_IRQ_ACT       0   /* interrupt pending                 */
-#define STAT_IRQ_NOACT     16  /* no interrupt pending              */
-#define STAT_IO_NOBUSY     0   /* no transfer busy                  */
-#define STAT_IO_BUSY       32  /* transfer busy                     */
-
-/* I/O command register bits */
-
-#define IOCMD_GO           128 /* Bit 7 = 1 -> start register xfer  */
-
-/* LANCE registers */
-
-#define LANCE_CSR0         0   /* Status/Control                    */
-
-#define CSR0_ERR           0x8000      /* general error flag                */
-#define CSR0_BABL          0x4000      /* transmitter timeout               */
-#define CSR0_CERR          0x2000      /* collision error                   */
-#define CSR0_MISS          0x1000      /* lost Rx block                     */
-#define CSR0_MERR          0x0800      /* memory access error               */
-#define CSR0_RINT          0x0400      /* receiver interrupt                */
-#define CSR0_TINT          0x0200      /* transmitter interrupt             */
-#define CSR0_IDON          0x0100      /* initialization done               */
-#define CSR0_INTR          0x0080      /* general interrupt flag            */
-#define CSR0_INEA          0x0040      /* interrupt enable                  */
-#define CSR0_RXON          0x0020      /* receiver enabled                  */
-#define CSR0_TXON          0x0010      /* transmitter enabled               */
-#define CSR0_TDMD          0x0008      /* force transmission now            */
-#define CSR0_STOP          0x0004      /* stop LANCE                        */
-#define CSR0_STRT          0x0002      /* start LANCE                       */
-#define CSR0_INIT          0x0001      /* read initialization block         */
-
-#define LANCE_CSR1         1   /* addr bit 0..15 of initialization  */
-#define LANCE_CSR2         2   /*          16..23 block             */
-
-#define LANCE_CSR3         3   /* Bus control                       */
-#define CSR3_BCON_HOLD     0   /* Bit 0 = 0 -> BM1,BM0,HOLD         */
-#define CSR3_BCON_BUSRQ    1   /* Bit 0 = 1 -> BUSAK0,BYTE,BUSRQ    */
-#define CSR3_ALE_HIGH      0   /* Bit 1 = 0 -> ALE asserted high    */
-#define CSR3_ALE_LOW       2   /* Bit 1 = 1 -> ALE asserted low     */
-#define CSR3_BSWAP_OFF     0   /* Bit 2 = 0 -> no byte swap         */
-#define CSR3_BSWAP_ON      4   /* Bit 2 = 1 -> byte swap            */
-
-/* LANCE structures */
-
-typedef struct {               /* LANCE initialization block        */
-       u16 Mode;               /* mode flags                        */
-       u8 PAdr[6];             /* MAC address                       */
-       u8 LAdrF[8];            /* Multicast filter                  */
-       u32 RdrP;               /* Receive descriptor                */
-       u32 TdrP;               /* Transmit descriptor               */
-} LANCE_InitBlock;
-
-/* Mode flags init block */
-
-#define LANCE_INIT_PROM    0x8000      /* enable promiscous mode            */
-#define LANCE_INIT_INTL    0x0040      /* internal loopback                 */
-#define LANCE_INIT_DRTY    0x0020      /* disable retry                     */
-#define LANCE_INIT_COLL    0x0010      /* force collision                   */
-#define LANCE_INIT_DTCR    0x0008      /* disable transmit CRC              */
-#define LANCE_INIT_LOOP    0x0004      /* loopback                          */
-#define LANCE_INIT_DTX     0x0002      /* disable transmitter               */
-#define LANCE_INIT_DRX     0x0001      /* disable receiver                  */
-
-typedef struct {               /* LANCE Tx descriptor               */
-       u16 LowAddr;            /* bit 0..15 of address              */
-       u16 Flags;              /* bit 16..23 of address + Flags     */
-       u16 Len;                /* 2s complement of packet length    */
-       u16 Status;             /* Result of transmission            */
-} LANCE_TxDescr;
-
-#define TXDSCR_FLAGS_OWN   0x8000      /* LANCE owns descriptor             */
-#define TXDSCR_FLAGS_ERR   0x4000      /* summary error flag                */
-#define TXDSCR_FLAGS_MORE  0x1000      /* more than one retry needed?       */
-#define TXDSCR_FLAGS_ONE   0x0800      /* one retry?                        */
-#define TXDSCR_FLAGS_DEF   0x0400      /* transmission deferred?            */
-#define TXDSCR_FLAGS_STP   0x0200      /* first packet in chain?            */
-#define TXDSCR_FLAGS_ENP   0x0100      /* last packet in chain?             */
-
-#define TXDSCR_STATUS_BUFF 0x8000      /* buffer error?                     */
-#define TXDSCR_STATUS_UFLO 0x4000      /* silo underflow during transmit?   */
-#define TXDSCR_STATUS_LCOL 0x1000      /* late collision?                   */
-#define TXDSCR_STATUS_LCAR 0x0800      /* loss of carrier?                  */
-#define TXDSCR_STATUS_RTRY 0x0400      /* retry error?                      */
-
-typedef struct {               /* LANCE Rx descriptor               */
-       u16 LowAddr;            /* bit 0..15 of address              */
-       u16 Flags;              /* bit 16..23 of address + Flags     */
-       u16 MaxLen;             /* 2s complement of buffer length    */
-       u16 Len;                /* packet length                     */
-} LANCE_RxDescr;
-
-#define RXDSCR_FLAGS_OWN   0x8000      /* LANCE owns descriptor             */
-#define RXDSCR_FLAGS_ERR   0x4000      /* summary error flag                */
-#define RXDSCR_FLAGS_FRAM  0x2000      /* framing error flag                */
-#define RXDSCR_FLAGS_OFLO  0x1000      /* FIFO overflow?                    */
-#define RXDSCR_FLAGS_CRC   0x0800      /* CRC error?                        */
-#define RXDSCR_FLAGS_BUFF  0x0400      /* buffer error?                     */
-#define RXDSCR_FLAGS_STP   0x0200      /* first packet in chain?            */
-#define RXDCSR_FLAGS_ENP   0x0100      /* last packet in chain?             */
-
-/* RAM layout */
-
-#define TXCOUNT            4   /* length of TX descriptor queue     */
-#define LTXCOUNT           2   /* log2 of it                        */
-#define RXCOUNT            4   /* length of RX descriptor queue     */
-#define LRXCOUNT           2   /* log2 of it                        */
-
-#define RAM_INITBASE       0   /* LANCE init block                  */
-#define RAM_TXBASE         24  /* Start of TX descriptor queue      */
-#define RAM_RXBASE         \
-(RAM_TXBASE + (TXCOUNT * 8))   /* Start of RX descriptor queue      */
-#define RAM_DATABASE       \
-(RAM_RXBASE + (RXCOUNT * 8))   /* Start of data area for frames     */
-#define RAM_BUFSIZE        1580        /* max. frame size - should never be
-                                  reached                           */
-
-#endif                         /* _SK_MCA_DRIVER_ */
-
-#endif /* _SK_MCA_INCLUDE_ */
diff --git a/drivers/net/skfp/can.c b/drivers/net/skfp/can.c
deleted file mode 100644 (file)
index 8a49abc..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/******************************************************************************
- *
- *     (C)Copyright 1998,1999 SysKonnect,
- *     a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- *     See the file "skfddi.c" for further 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.
- *
- *     The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-#ifndef        lint
-static const char xID_sccs[] = "@(#)can.c      1.5 97/04/07 (C) SK " ;
-#endif
-
-/*
- * canonical bit order
- */
-const u_char canonical[256] = {
-       0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,
-       0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
-       0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,
-       0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
-       0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,
-       0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
-       0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,
-       0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
-       0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,
-       0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
-       0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,
-       0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
-       0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,
-       0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
-       0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,
-       0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
-       0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,
-       0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
-       0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,
-       0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
-       0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,
-       0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
-       0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,
-       0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
-       0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,
-       0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
-       0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,
-       0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
-       0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,
-       0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
-       0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,
-       0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
-} ;
-
-#ifdef MAKE_TABLE
-int byte_reverse(x)
-int x ;
-{
-       int     y = 0 ;
-
-       if (x & 0x01)
-               y |= 0x80 ;
-       if (x & 0x02)
-               y |= 0x40 ;
-       if (x & 0x04)
-               y |= 0x20 ;
-       if (x & 0x08)
-               y |= 0x10 ;
-       if (x & 0x10)
-               y |= 0x08 ;
-       if (x & 0x20)
-               y |= 0x04 ;
-       if (x & 0x40)
-               y |= 0x02 ;
-       if (x & 0x80)
-               y |= 0x01 ;
-       return(y) ;
-}
-#endif
index 5b47583..4fe624b 100644 (file)
@@ -23,6 +23,7 @@
 #include "h/smc.h"
 #include "h/supern_2.h"
 #include "h/skfbiinc.h"
+#include <linux/bitrev.h>
 
 #ifndef        lint
 static const char ID_sccs[] = "@(#)drvfbi.c    1.63 99/02/11 (C) SK " ;
@@ -445,16 +446,14 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
        char PmdType ;
        int     i ;
 
-       extern const u_char canonical[256] ;
-
 #if    (defined(ISA) || defined(MCA))
        for (i = 0; i < 4 ;i++) {       /* read mac address from board */
                smc->hw.fddi_phys_addr.a[i] =
-                       canonical[(inpw(PR_A(i+SA_MAC))&0xff)] ;
+                       bitrev8(inpw(PR_A(i+SA_MAC)));
        }
        for (i = 4; i < 6; i++) {
                smc->hw.fddi_phys_addr.a[i] =
-                       canonical[(inpw(PR_A(i+SA_MAC+PRA_OFF))&0xff)] ;
+                       bitrev8(inpw(PR_A(i+SA_MAC+PRA_OFF)));
        }
 #endif
 #ifdef EISA
@@ -464,17 +463,17 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
         */
        for (i = 0; i < 4 ;i++) {       /* read mac address from board */
                smc->hw.fddi_phys_addr.a[i] =
-                       canonical[inp(PR_A(i+SA_MAC))] ;
+                       bitrev8(inp(PR_A(i+SA_MAC)));
        }
        for (i = 4; i < 6; i++) {
                smc->hw.fddi_phys_addr.a[i] =
-                       canonical[inp(PR_A(i+SA_MAC+PRA_OFF))] ;
+                       bitrev8(inp(PR_A(i+SA_MAC+PRA_OFF)));
        }
 #endif
 #ifdef PCI
        for (i = 0; i < 6; i++) {       /* read mac address from board */
                smc->hw.fddi_phys_addr.a[i] =
-                       canonical[inp(ADDR(B2_MAC_0+i))] ;
+                       bitrev8(inp(ADDR(B2_MAC_0+i)));
        }
 #endif
 #ifndef        PCI
@@ -493,7 +492,7 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
        if (mac_addr) {
                for (i = 0; i < 6 ;i++) {
                        smc->hw.fddi_canon_addr.a[i] = mac_addr[i] ;
-                       smc->hw.fddi_home_addr.a[i] = canonical[mac_addr[i]] ;
+                       smc->hw.fddi_home_addr.a[i] = bitrev8(mac_addr[i]);
                }
                return ;
        }
@@ -501,7 +500,7 @@ void read_address(struct s_smc *smc, u_char *mac_addr)
 
        for (i = 0; i < 6 ;i++) {
                smc->hw.fddi_canon_addr.a[i] =
-                       canonical[smc->hw.fddi_phys_addr.a[i]] ;
+                       bitrev8(smc->hw.fddi_phys_addr.a[i]);
        }
 }
 
@@ -1269,11 +1268,8 @@ void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr)
 {
        int i ;
 
-       extern const u_char canonical[256] ;
-
-       for (i = 0 ; i < 6 ; i++) {
-               bia_addr->a[i] = canonical[smc->hw.fddi_phys_addr.a[i]] ;
-       }
+       for (i = 0 ; i < 6 ; i++)
+               bia_addr->a[i] = bitrev8(smc->hw.fddi_phys_addr.a[i]);
 }
 
 void smt_start_watchdog(struct s_smc *smc)
index 0784f55..a45205d 100644 (file)
@@ -22,7 +22,7 @@
 #include "h/fddi.h"
 #include "h/smc.h"
 #include "h/supern_2.h"
-#include "can.c"
+#include <linux/bitrev.h>
 
 #ifndef        lint
 static const char ID_sccs[] = "@(#)fplustm.c   1.32 99/02/23 (C) SK " ;
@@ -1073,7 +1073,7 @@ static struct s_fpmc* mac_get_mc_table(struct s_smc *smc,
        if (can) {
                p = own->a ;
                for (i = 0 ; i < 6 ; i++, p++)
-                       *p = canonical[*p] ;
+                       *p = bitrev8(*p);
        }
        slot = NULL;
        for (i = 0, tb = smc->hw.fp.mc.table ; i < FPMAX_MULTICAST ; i++, tb++){
index 99a776a..fe84780 100644 (file)
@@ -18,6 +18,7 @@
 #include "h/fddi.h"
 #include "h/smc.h"
 #include "h/smt_p.h"
+#include <linux/bitrev.h>
 
 #define KERNEL
 #include "h/smtstate.h"
@@ -26,8 +27,6 @@
 static const char ID_sccs[] = "@(#)smt.c       2.43 98/11/23 (C) SK " ;
 #endif
 
-extern const u_char canonical[256] ;
-
 /*
  * FC in SMbuf
  */
@@ -180,7 +179,7 @@ void smt_agent_init(struct s_smc *smc)
        driver_get_bia(smc,&smc->mib.fddiSMTStationId.sid_node) ;
        for (i = 0 ; i < 6 ; i ++) {
                smc->mib.fddiSMTStationId.sid_node.a[i] =
-                       canonical[smc->mib.fddiSMTStationId.sid_node.a[i]] ;
+                       bitrev8(smc->mib.fddiSMTStationId.sid_node.a[i]);
        }
        smc->mib.fddiSMTManufacturerData[0] =
                smc->mib.fddiSMTStationId.sid_node.a[0] ;
@@ -2049,9 +2048,8 @@ static void hwm_conv_can(struct s_smc *smc, char *data, int len)
 
        SK_UNUSED(smc) ;
 
-       for (i = len; i ; i--, data++) {
-               *data = canonical[*(u_char *)data] ;
-       }
+       for (i = len; i ; i--, data++)
+               *data = bitrev8(*data);
 }
 #endif
 
index 45283f3..e482e7f 100644 (file)
@@ -42,7 +42,7 @@
 #include "skge.h"
 
 #define DRV_NAME               "skge"
-#define DRV_VERSION            "1.9"
+#define DRV_VERSION            "1.10"
 #define PFX                    DRV_NAME " "
 
 #define DEFAULT_TX_RING_SIZE   128
@@ -132,18 +132,93 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs,
 }
 
 /* Wake on Lan only supported on Yukon chips with rev 1 or above */
-static int wol_supported(const struct skge_hw *hw)
+static u32 wol_supported(const struct skge_hw *hw)
 {
-       return !((hw->chip_id == CHIP_ID_GENESIS ||
-                 (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)));
+       if (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev != 0)
+               return WAKE_MAGIC | WAKE_PHY;
+       else
+               return 0;
+}
+
+static u32 pci_wake_enabled(struct pci_dev *dev)
+{
+       int pm = pci_find_capability(dev, PCI_CAP_ID_PM);
+       u16 value;
+
+       /* If device doesn't support PM Capabilities, but request is to disable
+        * wake events, it's a nop; otherwise fail */
+       if (!pm)
+               return 0;
+
+       pci_read_config_word(dev, pm + PCI_PM_PMC, &value);
+
+       value &= PCI_PM_CAP_PME_MASK;
+       value >>= ffs(PCI_PM_CAP_PME_MASK) - 1;   /* First bit of mask */
+
+       return value != 0;
+}
+
+static void skge_wol_init(struct skge_port *skge)
+{
+       struct skge_hw *hw = skge->hw;
+       int port = skge->port;
+       enum pause_control save_mode;
+       u32 ctrl;
+
+       /* Bring hardware out of reset */
+       skge_write16(hw, B0_CTST, CS_RST_CLR);
+       skge_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR);
+
+       skge_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+       skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+       /* Force to 10/100 skge_reset will re-enable on resume   */
+       save_mode = skge->flow_control;
+       skge->flow_control = FLOW_MODE_SYMMETRIC;
+
+       ctrl = skge->advertising;
+       skge->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
+
+       skge_phy_reset(skge);
+
+       skge->flow_control = save_mode;
+       skge->advertising = ctrl;
+
+       /* Set GMAC to no flow control and auto update for speed/duplex */
+       gma_write16(hw, port, GM_GP_CTRL,
+                   GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA|
+                   GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS);
+
+       /* Set WOL address */
+       memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR),
+                   skge->netdev->dev_addr, ETH_ALEN);
+
+       /* Turn on appropriate WOL control bits */
+       skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT);
+       ctrl = 0;
+       if (skge->wol & WAKE_PHY)
+               ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT;
+       else
+               ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT;
+
+       if (skge->wol & WAKE_MAGIC)
+               ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT;
+       else
+               ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;;
+
+       ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT;
+       skge_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
+
+       /* block receiver */
+       skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
 }
 
 static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct skge_port *skge = netdev_priv(dev);
 
-       wol->supported = wol_supported(skge->hw) ? WAKE_MAGIC : 0;
-       wol->wolopts = skge->wol ? WAKE_MAGIC : 0;
+       wol->supported = wol_supported(skge->hw);
+       wol->wolopts = skge->wol;
 }
 
 static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -151,23 +226,12 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
        struct skge_port *skge = netdev_priv(dev);
        struct skge_hw *hw = skge->hw;
 
-       if (wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
+       if (wol->wolopts & wol_supported(hw))
                return -EOPNOTSUPP;
 
-       if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw))
-               return -EOPNOTSUPP;
-
-       skge->wol = wol->wolopts == WAKE_MAGIC;
-
-       if (skge->wol) {
-               memcpy_toio(hw->regs + WOL_MAC_ADDR, dev->dev_addr, ETH_ALEN);
-
-               skge_write16(hw, WOL_CTRL_STAT,
-                            WOL_CTL_ENA_PME_ON_MAGIC_PKT |
-                            WOL_CTL_ENA_MAGIC_PKT_UNIT);
-       } else
-               skge_write16(hw, WOL_CTRL_STAT, WOL_CTL_DEFAULT);
-
+       skge->wol = wol->wolopts;
+       if (!netif_running(dev))
+               skge_wol_init(skge);
        return 0;
 }
 
@@ -2373,6 +2437,9 @@ static int skge_up(struct net_device *dev)
        size_t rx_size, tx_size;
        int err;
 
+       if (!is_valid_ether_addr(dev->dev_addr))
+               return -EINVAL;
+
        if (netif_msg_ifup(skge))
                printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
 
@@ -2392,7 +2459,7 @@ static int skge_up(struct net_device *dev)
        BUG_ON(skge->dma & 7);
 
        if ((u64)skge->dma >> 32 != ((u64) skge->dma + skge->mem_size) >> 32) {
-               printk(KERN_ERR PFX "pci_alloc_consistent region crosses 4G boundary\n");
+               dev_err(&hw->pdev->dev, "pci_alloc_consistent region crosses 4G boundary\n");
                err = -EINVAL;
                goto free_pci_mem;
        }
@@ -3001,6 +3068,7 @@ static void skge_mac_intr(struct skge_hw *hw, int port)
 /* Handle device specific framing and timeout interrupts */
 static void skge_error_irq(struct skge_hw *hw)
 {
+       struct pci_dev *pdev = hw->pdev;
        u32 hwstatus = skge_read32(hw, B0_HWE_ISRC);
 
        if (hw->chip_id == CHIP_ID_GENESIS) {
@@ -3016,12 +3084,12 @@ static void skge_error_irq(struct skge_hw *hw)
        }
 
        if (hwstatus & IS_RAM_RD_PAR) {
-               printk(KERN_ERR PFX "Ram read data parity error\n");
+               dev_err(&pdev->dev, "Ram read data parity error\n");
                skge_write16(hw, B3_RI_CTRL, RI_CLR_RD_PERR);
        }
 
        if (hwstatus & IS_RAM_WR_PAR) {
-               printk(KERN_ERR PFX "Ram write data parity error\n");
+               dev_err(&pdev->dev, "Ram write data parity error\n");
                skge_write16(hw, B3_RI_CTRL, RI_CLR_WR_PERR);
        }
 
@@ -3032,38 +3100,38 @@ static void skge_error_irq(struct skge_hw *hw)
                skge_mac_parity(hw, 1);
 
        if (hwstatus & IS_R1_PAR_ERR) {
-               printk(KERN_ERR PFX "%s: receive queue parity error\n",
-                      hw->dev[0]->name);
+               dev_err(&pdev->dev, "%s: receive queue parity error\n",
+                       hw->dev[0]->name);
                skge_write32(hw, B0_R1_CSR, CSR_IRQ_CL_P);
        }
 
        if (hwstatus & IS_R2_PAR_ERR) {
-               printk(KERN_ERR PFX "%s: receive queue parity error\n",
-                      hw->dev[1]->name);
+               dev_err(&pdev->dev, "%s: receive queue parity error\n",
+                       hw->dev[1]->name);
                skge_write32(hw, B0_R2_CSR, CSR_IRQ_CL_P);
        }
 
        if (hwstatus & (IS_IRQ_MST_ERR|IS_IRQ_STAT)) {
                u16 pci_status, pci_cmd;
 
-               pci_read_config_word(hw->pdev, PCI_COMMAND, &pci_cmd);
-               pci_read_config_word(hw->pdev, PCI_STATUS, &pci_status);
+               pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
+               pci_read_config_word(pdev, PCI_STATUS, &pci_status);
 
-               printk(KERN_ERR PFX "%s: PCI error cmd=%#x status=%#x\n",
-                              pci_name(hw->pdev), pci_cmd, pci_status);
+               dev_err(&pdev->dev, "PCI error cmd=%#x status=%#x\n",
+                       pci_cmd, pci_status);
 
                /* Write the error bits back to clear them. */
                pci_status &= PCI_STATUS_ERROR_BITS;
                skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-               pci_write_config_word(hw->pdev, PCI_COMMAND,
+               pci_write_config_word(pdev, PCI_COMMAND,
                                      pci_cmd | PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
-               pci_write_config_word(hw->pdev, PCI_STATUS, pci_status);
+               pci_write_config_word(pdev, PCI_STATUS, pci_status);
                skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
 
                /* if error still set then just ignore it */
                hwstatus = skge_read32(hw, B0_HWE_ISRC);
                if (hwstatus & IS_IRQ_STAT) {
-                       printk(KERN_INFO PFX "unable to clear error (so ignoring them)\n");
+                       dev_warn(&hw->pdev->dev, "unable to clear error (so ignoring them)\n");
                        hw->intr_mask &= ~IS_HW_ERR;
                }
        }
@@ -3277,8 +3345,8 @@ static int skge_reset(struct skge_hw *hw)
                        hw->phy_addr = PHY_ADDR_BCOM;
                        break;
                default:
-                       printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
-                              pci_name(hw->pdev), hw->phy_type);
+                       dev_err(&hw->pdev->dev, "unsupported phy type 0x%x\n",
+                              hw->phy_type);
                        return -EOPNOTSUPP;
                }
                break;
@@ -3293,8 +3361,8 @@ static int skge_reset(struct skge_hw *hw)
                break;
 
        default:
-               printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n",
-                      pci_name(hw->pdev), hw->chip_id);
+               dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
+                      hw->chip_id);
                return -EOPNOTSUPP;
        }
 
@@ -3334,7 +3402,7 @@ static int skge_reset(struct skge_hw *hw)
                /* avoid boards with stuck Hardware error bits */
                if ((skge_read32(hw, B0_ISRC) & IS_HW_ERR) &&
                    (skge_read32(hw, B0_HWE_ISRC) & IS_IRQ_SENSOR)) {
-                       printk(KERN_WARNING PFX "stuck hardware sensor bit\n");
+                       dev_warn(&hw->pdev->dev, "stuck hardware sensor bit\n");
                        hw->intr_mask &= ~IS_HW_ERR;
                }
 
@@ -3408,7 +3476,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
        struct net_device *dev = alloc_etherdev(sizeof(*skge));
 
        if (!dev) {
-               printk(KERN_ERR "skge etherdev alloc failed");
+               dev_err(&hw->pdev->dev, "etherdev alloc failed\n");
                return NULL;
        }
 
@@ -3452,6 +3520,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
        skge->duplex = -1;
        skge->speed = -1;
        skge->advertising = skge_supported_modes(hw);
+       skge->wol = pci_wake_enabled(hw->pdev) ? wol_supported(hw) : 0;
 
        hw->dev[port] = dev;
 
@@ -3496,15 +3565,13 @@ static int __devinit skge_probe(struct pci_dev *pdev,
 
        err = pci_enable_device(pdev);
        if (err) {
-               printk(KERN_ERR PFX "%s cannot enable PCI device\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "cannot enable PCI device\n");
                goto err_out;
        }
 
        err = pci_request_regions(pdev, DRV_NAME);
        if (err) {
-               printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "cannot obtain PCI resources\n");
                goto err_out_disable_pdev;
        }
 
@@ -3519,8 +3586,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
        }
 
        if (err) {
-               printk(KERN_ERR PFX "%s no usable DMA configuration\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "no usable DMA configuration\n");
                goto err_out_free_regions;
        }
 
@@ -3538,8 +3604,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
        err = -ENOMEM;
        hw = kzalloc(sizeof(*hw), GFP_KERNEL);
        if (!hw) {
-               printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "cannot allocate hardware struct\n");
                goto err_out_free_regions;
        }
 
@@ -3550,8 +3615,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
 
        hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
        if (!hw->regs) {
-               printk(KERN_ERR PFX "%s: cannot map device registers\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "cannot map device registers\n");
                goto err_out_free_hw;
        }
 
@@ -3567,23 +3631,19 @@ static int __devinit skge_probe(struct pci_dev *pdev,
        if (!dev)
                goto err_out_led_off;
 
-       if (!is_valid_ether_addr(dev->dev_addr)) {
-               printk(KERN_ERR PFX "%s: bad (zero?) ethernet address in rom\n",
-                      pci_name(pdev));
-               err = -EIO;
-               goto err_out_free_netdev;
-       }
+       /* Some motherboards are broken and has zero in ROM. */
+       if (!is_valid_ether_addr(dev->dev_addr))
+               dev_warn(&pdev->dev, "bad (zero?) ethernet address in rom\n");
 
        err = register_netdev(dev);
        if (err) {
-               printk(KERN_ERR PFX "%s: cannot register net device\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "cannot register net device\n");
                goto err_out_free_netdev;
        }
 
        err = request_irq(pdev->irq, skge_intr, IRQF_SHARED, dev->name, hw);
        if (err) {
-               printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
+               dev_err(&pdev->dev, "%s: cannot assign irq %d\n",
                       dev->name, pdev->irq);
                goto err_out_unregister;
        }
@@ -3594,7 +3654,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
                        skge_show_addr(dev1);
                else {
                        /* Failure to register second port need not be fatal */
-                       printk(KERN_WARNING PFX "register of second port failed\n");
+                       dev_warn(&pdev->dev, "register of second port failed\n");
                        hw->dev[1] = NULL;
                        free_netdev(dev1);
                }
@@ -3659,28 +3719,46 @@ static void __devexit skge_remove(struct pci_dev *pdev)
 }
 
 #ifdef CONFIG_PM
+static int vaux_avail(struct pci_dev *pdev)
+{
+       int pm_cap;
+
+       pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
+       if (pm_cap) {
+               u16 ctl;
+               pci_read_config_word(pdev, pm_cap + PCI_PM_PMC, &ctl);
+               if (ctl & PCI_PM_CAP_AUX_POWER)
+                       return 1;
+       }
+       return 0;
+}
+
+
 static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct skge_hw *hw  = pci_get_drvdata(pdev);
-       int i, wol = 0;
+       int i, err, wol = 0;
+
+       err = pci_save_state(pdev);
+       if (err)
+               return err;
 
-       pci_save_state(pdev);
        for (i = 0; i < hw->ports; i++) {
                struct net_device *dev = hw->dev[i];
+               struct skge_port *skge = netdev_priv(dev);
 
-               if (netif_running(dev)) {
-                       struct skge_port *skge = netdev_priv(dev);
+               if (netif_running(dev))
+                       skge_down(dev);
+               if (skge->wol)
+                       skge_wol_init(skge);
 
-                       netif_carrier_off(dev);
-                       if (skge->wol)
-                               netif_stop_queue(dev);
-                       else
-                               skge_down(dev);
-                       wol |= skge->wol;
-               }
-               netif_device_detach(dev);
+               wol |= skge->wol;
        }
 
+       if (wol && vaux_avail(pdev))
+               skge_write8(hw, B0_POWER_CTRL,
+                           PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_ON | PC_VCC_OFF);
+
        skge_write32(hw, B0_IMSK, 0);
        pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
        pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -3693,8 +3771,14 @@ static int skge_resume(struct pci_dev *pdev)
        struct skge_hw *hw  = pci_get_drvdata(pdev);
        int i, err;
 
-       pci_set_power_state(pdev, PCI_D0);
-       pci_restore_state(pdev);
+       err = pci_set_power_state(pdev, PCI_D0);
+       if (err)
+               goto out;
+
+       err = pci_restore_state(pdev);
+       if (err)
+               goto out;
+
        pci_enable_wake(pdev, PCI_D0, 0);
 
        err = skge_reset(hw);
@@ -3704,7 +3788,6 @@ static int skge_resume(struct pci_dev *pdev)
        for (i = 0; i < hw->ports; i++) {
                struct net_device *dev = hw->dev[i];
 
-               netif_device_attach(dev);
                if (netif_running(dev)) {
                        err = skge_up(dev);
 
index f6223c5..17b1b47 100644 (file)
@@ -876,11 +876,13 @@ enum {
        WOL_PATT_CNT_0  = 0x0f38,/* 32 bit      WOL Pattern Counter 3..0 */
        WOL_PATT_CNT_4  = 0x0f3c,/* 24 bit      WOL Pattern Counter 6..4 */
 };
+#define WOL_REGS(port, x)      (x + (port)*0x80)
 
 enum {
        WOL_PATT_RAM_1  = 0x1000,/*  WOL Pattern RAM Link 1 */
        WOL_PATT_RAM_2  = 0x1400,/*  WOL Pattern RAM Link 2 */
 };
+#define WOL_PATT_RAM_BASE(port)        (WOL_PATT_RAM_1 + (port)*0x400)
 
 enum {
        BASE_XMAC_1     = 0x2000,/* XMAC 1 registers */
index 822dd0b..f2ab3d5 100644 (file)
@@ -49,7 +49,7 @@
 #include "sky2.h"
 
 #define DRV_NAME               "sky2"
-#define DRV_VERSION            "1.10"
+#define DRV_VERSION            "1.12"
 #define PFX                    DRV_NAME " "
 
 /*
@@ -105,6 +105,7 @@ static const struct pci_device_id sky2_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4b00) },    /* DGE-560T */
        { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4001) },    /* DGE-550SX */
        { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B02) },    /* DGE-560SX */
+       { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x4B03) },    /* DGE-550T */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4340) }, /* 88E8021 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4341) }, /* 88E8022 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4342) }, /* 88E8061 */
@@ -126,6 +127,9 @@ static const struct pci_device_id sky2_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4366) }, /* 88EC036 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4367) }, /* 88EC032 */
        { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4368) }, /* 88EC034 */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4369) }, /* 88EC042 */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436A) }, /* 88E8058 */
+       { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x436B) }, /* 88E8071 */
        { 0 }
 };
 
@@ -140,7 +144,7 @@ static const u32 portirq_msk[] = { Y2_IS_PORT_1, Y2_IS_PORT_2 };
 static const char *yukon2_name[] = {
        "XL",           /* 0xb3 */
        "EC Ultra",     /* 0xb4 */
-       "UNKNOWN",      /* 0xb5 */
+       "Extreme",      /* 0xb5 */
        "EC",           /* 0xb6 */
        "FE",           /* 0xb7 */
 };
@@ -192,76 +196,52 @@ static u16 gm_phy_read(struct sky2_hw *hw, unsigned port, u16 reg)
        return v;
 }
 
-static void sky2_set_power_state(struct sky2_hw *hw, pci_power_t state)
-{
-       u16 power_control;
-       int vaux;
-
-       pr_debug("sky2_set_power_state %d\n", state);
-       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
-
-       power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_PMC);
-       vaux = (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL) &&
-               (power_control & PCI_PM_CAP_PME_D3cold);
-
-       power_control = sky2_pci_read16(hw, hw->pm_cap + PCI_PM_CTRL);
-
-       power_control |= PCI_PM_CTRL_PME_STATUS;
-       power_control &= ~(PCI_PM_CTRL_STATE_MASK);
 
-       switch (state) {
-       case PCI_D0:
-               /* switch power to VCC (WA for VAUX problem) */
-               sky2_write8(hw, B0_POWER_CTRL,
-                           PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
-
-               /* disable Core Clock Division, */
-               sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
-
-               if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
-                       /* enable bits are inverted */
-                       sky2_write8(hw, B2_Y2_CLK_GATE,
-                                   Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
-                                   Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
-                                   Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
-               else
-                       sky2_write8(hw, B2_Y2_CLK_GATE, 0);
+static void sky2_power_on(struct sky2_hw *hw)
+{
+       /* switch power to VCC (WA for VAUX problem) */
+       sky2_write8(hw, B0_POWER_CTRL,
+                   PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
 
-               if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
-                       u32 reg1;
+       /* disable Core Clock Division, */
+       sky2_write32(hw, B2_Y2_CLK_CTRL, Y2_CLK_DIV_DIS);
 
-                       sky2_pci_write32(hw, PCI_DEV_REG3, 0);
-                       reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
-                       reg1 &= P_ASPM_CONTROL_MSK;
-                       sky2_pci_write32(hw, PCI_DEV_REG4, reg1);
-                       sky2_pci_write32(hw, PCI_DEV_REG5, 0);
-               }
+       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+               /* enable bits are inverted */
+               sky2_write8(hw, B2_Y2_CLK_GATE,
+                           Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
+                           Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
+                           Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
+       else
+               sky2_write8(hw, B2_Y2_CLK_GATE, 0);
 
-               break;
+       if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
+               u32 reg1;
 
-       case PCI_D3hot:
-       case PCI_D3cold:
-               if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
-                       sky2_write8(hw, B2_Y2_CLK_GATE, 0);
-               else
-                       /* enable bits are inverted */
-                       sky2_write8(hw, B2_Y2_CLK_GATE,
-                                   Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
-                                   Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
-                                   Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
-
-               /* switch power to VAUX */
-               if (vaux && state != PCI_D3cold)
-                       sky2_write8(hw, B0_POWER_CTRL,
-                                   (PC_VAUX_ENA | PC_VCC_ENA |
-                                    PC_VAUX_ON | PC_VCC_OFF));
-               break;
-       default:
-               printk(KERN_ERR PFX "Unknown power state %d\n", state);
+               sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+               reg1 = sky2_pci_read32(hw, PCI_DEV_REG4);
+               reg1 &= P_ASPM_CONTROL_MSK;
+               sky2_pci_write32(hw, PCI_DEV_REG4, reg1);
+               sky2_pci_write32(hw, PCI_DEV_REG5, 0);
        }
+}
 
-       sky2_pci_write16(hw, hw->pm_cap + PCI_PM_CTRL, power_control);
-       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+static void sky2_power_aux(struct sky2_hw *hw)
+{
+       if (hw->chip_id == CHIP_ID_YUKON_XL && hw->chip_rev > 1)
+               sky2_write8(hw, B2_Y2_CLK_GATE, 0);
+       else
+               /* enable bits are inverted */
+               sky2_write8(hw, B2_Y2_CLK_GATE,
+                           Y2_PCI_CLK_LNK1_DIS | Y2_COR_CLK_LNK1_DIS |
+                           Y2_CLK_GAT_LNK1_DIS | Y2_PCI_CLK_LNK2_DIS |
+                           Y2_COR_CLK_LNK2_DIS | Y2_CLK_GAT_LNK2_DIS);
+
+       /* switch power to VAUX */
+       if (sky2_read16(hw, B0_CTST) & Y2_VAUX_AVAIL)
+               sky2_write8(hw, B0_POWER_CTRL,
+                           (PC_VAUX_ENA | PC_VCC_ENA |
+                            PC_VAUX_ON | PC_VCC_OFF));
 }
 
 static void sky2_gmac_reset(struct sky2_hw *hw, unsigned port)
@@ -313,8 +293,10 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
        struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
        u16 ctrl, ct1000, adv, pg, ledctrl, ledover, reg;
 
-       if (sky2->autoneg == AUTONEG_ENABLE &&
-           !(hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
+       if (sky2->autoneg == AUTONEG_ENABLE
+           && !(hw->chip_id == CHIP_ID_YUKON_XL
+                || hw->chip_id == CHIP_ID_YUKON_EC_U
+                || hw->chip_id == CHIP_ID_YUKON_EX)) {
                u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
 
                ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
@@ -341,8 +323,10 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                        /* enable automatic crossover */
                        ctrl |= PHY_M_PC_MDI_XMODE(PHY_M_PC_ENA_AUTO);
 
-                       if (sky2->autoneg == AUTONEG_ENABLE &&
-                           (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)) {
+                       if (sky2->autoneg == AUTONEG_ENABLE
+                           && (hw->chip_id == CHIP_ID_YUKON_XL
+                               || hw->chip_id == CHIP_ID_YUKON_EC_U
+                               || hw->chip_id == CHIP_ID_YUKON_EX)) {
                                ctrl &= ~PHY_M_PC_DSC_MSK;
                                ctrl |= PHY_M_PC_DSC(2) | PHY_M_PC_DOWN_S_ENA;
                        }
@@ -497,7 +481,9 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
                /* restore page register */
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
                break;
+
        case CHIP_ID_YUKON_EC_U:
+       case CHIP_ID_YUKON_EX:
                pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
 
                /* select page 3 to access LED control register */
@@ -539,7 +525,7 @@ static void sky2_phy_init(struct sky2_hw *hw, unsigned port)
 
                /* set page register to 0 */
                gm_phy_write(hw, port, PHY_MARV_EXT_ADR, pg);
-       } else {
+       } else if (hw->chip_id != CHIP_ID_YUKON_EX) {
                gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
 
                if (sky2->autoneg == AUTONEG_DISABLE || sky2->speed == SPEED_100) {
@@ -591,6 +577,73 @@ static void sky2_phy_reinit(struct sky2_port *sky2)
        spin_unlock_bh(&sky2->phy_lock);
 }
 
+/* Put device in state to listen for Wake On Lan */
+static void sky2_wol_init(struct sky2_port *sky2)
+{
+       struct sky2_hw *hw = sky2->hw;
+       unsigned port = sky2->port;
+       enum flow_control save_mode;
+       u16 ctrl;
+       u32 reg1;
+
+       /* Bring hardware out of reset */
+       sky2_write16(hw, B0_CTST, CS_RST_CLR);
+       sky2_write16(hw, SK_REG(port, GMAC_LINK_CTRL), GMLC_RST_CLR);
+
+       sky2_write8(hw, SK_REG(port, GPHY_CTRL), GPC_RST_CLR);
+       sky2_write8(hw, SK_REG(port, GMAC_CTRL), GMC_RST_CLR);
+
+       /* Force to 10/100
+        * sky2_reset will re-enable on resume
+        */
+       save_mode = sky2->flow_mode;
+       ctrl = sky2->advertising;
+
+       sky2->advertising &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
+       sky2->flow_mode = FC_NONE;
+       sky2_phy_power(hw, port, 1);
+       sky2_phy_reinit(sky2);
+
+       sky2->flow_mode = save_mode;
+       sky2->advertising = ctrl;
+
+       /* Set GMAC to no flow control and auto update for speed/duplex */
+       gma_write16(hw, port, GM_GP_CTRL,
+                   GM_GPCR_FC_TX_DIS|GM_GPCR_TX_ENA|GM_GPCR_RX_ENA|
+                   GM_GPCR_DUP_FULL|GM_GPCR_FC_RX_DIS|GM_GPCR_AU_FCT_DIS);
+
+       /* Set WOL address */
+       memcpy_toio(hw->regs + WOL_REGS(port, WOL_MAC_ADDR),
+                   sky2->netdev->dev_addr, ETH_ALEN);
+
+       /* Turn on appropriate WOL control bits */
+       sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), WOL_CTL_CLEAR_RESULT);
+       ctrl = 0;
+       if (sky2->wol & WAKE_PHY)
+               ctrl |= WOL_CTL_ENA_PME_ON_LINK_CHG|WOL_CTL_ENA_LINK_CHG_UNIT;
+       else
+               ctrl |= WOL_CTL_DIS_PME_ON_LINK_CHG|WOL_CTL_DIS_LINK_CHG_UNIT;
+
+       if (sky2->wol & WAKE_MAGIC)
+               ctrl |= WOL_CTL_ENA_PME_ON_MAGIC_PKT|WOL_CTL_ENA_MAGIC_PKT_UNIT;
+       else
+               ctrl |= WOL_CTL_DIS_PME_ON_MAGIC_PKT|WOL_CTL_DIS_MAGIC_PKT_UNIT;;
+
+       ctrl |= WOL_CTL_DIS_PME_ON_PATTERN|WOL_CTL_DIS_PATTERN_UNIT;
+       sky2_write16(hw, WOL_REGS(port, WOL_CTRL_STAT), ctrl);
+
+       /* Turn on legacy PCI-Express PME mode */
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
+       reg1 = sky2_pci_read32(hw, PCI_DEV_REG1);
+       reg1 |= PCI_Y2_PME_LEGACY;
+       sky2_pci_write32(hw, PCI_DEV_REG1, reg1);
+       sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
+
+       /* block receiver */
+       sky2_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
+
+}
+
 static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
 {
        struct sky2_port *sky2 = netdev_priv(hw->dev[port]);
@@ -684,7 +737,7 @@ static void sky2_mac_init(struct sky2_hw *hw, unsigned port)
        sky2_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
        sky2_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
 
-       if (hw->chip_id == CHIP_ID_YUKON_EC_U) {
+       if (hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX) {
                sky2_write8(hw, SK_REG(port, RX_GMF_LP_THR), 768/8);
                sky2_write8(hw, SK_REG(port, RX_GMF_UP_THR), 1024/8);
                if (hw->dev[port]->mtu > ETH_DATA_LEN) {
@@ -1467,6 +1520,9 @@ static void sky2_tx_complete(struct sky2_port *sky2, u16 done)
                        if (unlikely(netif_msg_tx_done(sky2)))
                                printk(KERN_DEBUG "%s: tx done %u\n",
                                       dev->name, idx);
+                       sky2->net_stats.tx_packets++;
+                       sky2->net_stats.tx_bytes += re->skb->len;
+
                        dev_kfree_skb_any(re->skb);
                }
 
@@ -1641,7 +1697,9 @@ static void sky2_link_up(struct sky2_port *sky2)
        sky2_write8(hw, SK_REG(port, LNK_LED_REG),
                    LINKLED_ON | LINKLED_BLINK_OFF | LINKLED_LINKSYNC_OFF);
 
-       if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U) {
+       if (hw->chip_id == CHIP_ID_YUKON_XL
+           || hw->chip_id == CHIP_ID_YUKON_EC_U
+           || hw->chip_id == CHIP_ID_YUKON_EX) {
                u16 pg = gm_phy_read(hw, port, PHY_MARV_EXT_ADR);
                u16 led = PHY_M_LEDC_LOS_CTRL(1);       /* link active */
 
@@ -1734,14 +1792,16 @@ static int sky2_autoneg_done(struct sky2_port *sky2, u16 aux)
        sky2->duplex = (aux & PHY_M_PS_FULL_DUP) ? DUPLEX_FULL : DUPLEX_HALF;
 
        /* Pause bits are offset (9..8) */
-       if (hw->chip_id == CHIP_ID_YUKON_XL || hw->chip_id == CHIP_ID_YUKON_EC_U)
+       if (hw->chip_id == CHIP_ID_YUKON_XL
+           || hw->chip_id == CHIP_ID_YUKON_EC_U
+           || hw->chip_id == CHIP_ID_YUKON_EX)
                aux >>= 6;
 
        sky2->flow_status = sky2_flow(aux & PHY_M_PS_RX_P_EN,
                                      aux & PHY_M_PS_TX_P_EN);
 
        if (sky2->duplex == DUPLEX_HALF && sky2->speed < SPEED_1000
-           && hw->chip_id != CHIP_ID_YUKON_EC_U)
+           && !(hw->chip_id == CHIP_ID_YUKON_EC_U || hw->chip_id == CHIP_ID_YUKON_EX))
                sky2->flow_status = FC_NONE;
 
        if (aux & PHY_M_PS_RX_P_EN)
@@ -1794,48 +1854,37 @@ out:
 }
 
 
-/* Transmit timeout is only called if we are running, carries is up
+/* Transmit timeout is only called if we are running, carrier is up
  * and tx queue is full (stopped).
+ * Called with netif_tx_lock held.
  */
 static void sky2_tx_timeout(struct net_device *dev)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
        struct sky2_hw *hw = sky2->hw;
-       unsigned txq = txqaddr[sky2->port];
-       u16 report, done;
+       u32 imask;
 
        if (netif_msg_timer(sky2))
                printk(KERN_ERR PFX "%s: tx timeout\n", dev->name);
 
-       report = sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX);
-       done = sky2_read16(hw, Q_ADDR(txq, Q_DONE));
-
        printk(KERN_DEBUG PFX "%s: transmit ring %u .. %u report=%u done=%u\n",
-              dev->name,
-              sky2->tx_cons, sky2->tx_prod, report, done);
+              dev->name, sky2->tx_cons, sky2->tx_prod,
+              sky2_read16(hw, sky2->port == 0 ? STAT_TXA1_RIDX : STAT_TXA2_RIDX),
+              sky2_read16(hw, Q_ADDR(txqaddr[sky2->port], Q_DONE)));
 
-       if (report != done) {
-               printk(KERN_INFO PFX "status burst pending (irq moderation?)\n");
-
-               sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP);
-               sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
-       } else if (report != sky2->tx_cons) {
-               printk(KERN_INFO PFX "status report lost?\n");
+       imask = sky2_read32(hw, B0_IMSK);       /* block IRQ in hw */
+       sky2_write32(hw, B0_IMSK, 0);
+       sky2_read32(hw, B0_IMSK);
 
-               netif_tx_lock_bh(dev);
-               sky2_tx_complete(sky2, report);
-               netif_tx_unlock_bh(dev);
-       } else {
-               printk(KERN_INFO PFX "hardware hung? flushing\n");
+       netif_poll_disable(hw->dev[0]);         /* stop NAPI poll */
+       synchronize_irq(hw->pdev->irq);
 
-               sky2_write32(hw, Q_ADDR(txq, Q_CSR), BMU_STOP);
-               sky2_write32(hw, Y2_QADDR(txq, PREF_UNIT_CTRL), PREF_UNIT_RST_SET);
+       netif_start_queue(dev);                 /* don't wakeup during flush */
+       sky2_tx_complete(sky2, sky2->tx_prod);  /* Flush transmit queue */
 
-               sky2_tx_clean(dev);
+       sky2_write32(hw, B0_IMSK, imask);
 
-               sky2_qset(hw, txq);
-               sky2_prefetch_init(hw, txq, sky2->tx_le_map, TX_RING_SIZE - 1);
-       }
+       sky2_phy_reinit(sky2);                  /* this clears flow control etc */
 }
 
 static int sky2_change_mtu(struct net_device *dev, int new_mtu)
@@ -1849,8 +1898,9 @@ static int sky2_change_mtu(struct net_device *dev, int new_mtu)
        if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
                return -EINVAL;
 
+       /* TSO on Yukon Ultra and MTU > 1500 not supported */
        if (hw->chip_id == CHIP_ID_YUKON_EC_U && new_mtu > ETH_DATA_LEN)
-               return -EINVAL;
+               dev->features &= ~NETIF_F_TSO;
 
        if (!netif_running(dev)) {
                dev->mtu = new_mtu;
@@ -2089,6 +2139,8 @@ static int sky2_status_intr(struct sky2_hw *hw, int to_do)
                                goto force_update;
 
                        skb->protocol = eth_type_trans(skb, dev);
+                       sky2->net_stats.rx_packets++;
+                       sky2->net_stats.rx_bytes += skb->len;
                        dev->last_rx = jiffies;
 
 #ifdef SKY2_VLAN_TAG_USED
@@ -2218,8 +2270,8 @@ static void sky2_hw_intr(struct sky2_hw *hw)
 
                pci_err = sky2_pci_read16(hw, PCI_STATUS);
                if (net_ratelimit())
-                       printk(KERN_ERR PFX "%s: pci hw error (0x%x)\n",
-                              pci_name(hw->pdev), pci_err);
+                       dev_err(&hw->pdev->dev, "PCI hardware error (0x%x)\n",
+                               pci_err);
 
                sky2_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
                sky2_pci_write16(hw, PCI_STATUS,
@@ -2234,8 +2286,8 @@ static void sky2_hw_intr(struct sky2_hw *hw)
                pex_err = sky2_pci_read32(hw, PEX_UNC_ERR_STAT);
 
                if (net_ratelimit())
-                       printk(KERN_ERR PFX "%s: pci express error (0x%x)\n",
-                              pci_name(hw->pdev), pex_err);
+                       dev_err(&hw->pdev->dev, "PCI Express error (0x%x)\n",
+                               pex_err);
 
                /* clear the interrupt */
                sky2_write32(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
@@ -2404,6 +2456,7 @@ static inline u32 sky2_mhz(const struct sky2_hw *hw)
        switch (hw->chip_id) {
        case CHIP_ID_YUKON_EC:
        case CHIP_ID_YUKON_EC_U:
+       case CHIP_ID_YUKON_EX:
                return 125;     /* 125 Mhz */
        case CHIP_ID_YUKON_FE:
                return 100;     /* 100 Mhz */
@@ -2423,34 +2476,62 @@ static inline u32 sky2_clk2us(const struct sky2_hw *hw, u32 clk)
 }
 
 
-static int sky2_reset(struct sky2_hw *hw)
+static int __devinit sky2_init(struct sky2_hw *hw)
 {
-       u16 status;
        u8 t8;
-       int i;
 
        sky2_write8(hw, B0_CTST, CS_RST_CLR);
 
        hw->chip_id = sky2_read8(hw, B2_CHIP_ID);
        if (hw->chip_id < CHIP_ID_YUKON_XL || hw->chip_id > CHIP_ID_YUKON_FE) {
-               printk(KERN_ERR PFX "%s: unsupported chip type 0x%x\n",
-                      pci_name(hw->pdev), hw->chip_id);
+               dev_err(&hw->pdev->dev, "unsupported chip type 0x%x\n",
+                       hw->chip_id);
                return -EOPNOTSUPP;
        }
 
+       if (hw->chip_id == CHIP_ID_YUKON_EX)
+               dev_warn(&hw->pdev->dev, "this driver not yet tested on this chip type\n"
+                        "Please report success or failure to <netdev@vger.kernel.org>\n");
+
+       /* Make sure and enable all clocks */
+       if (hw->chip_id == CHIP_ID_YUKON_EX || hw->chip_id == CHIP_ID_YUKON_EC_U)
+               sky2_pci_write32(hw, PCI_DEV_REG3, 0);
+
        hw->chip_rev = (sky2_read8(hw, B2_MAC_CFG) & CFG_CHIP_R_MSK) >> 4;
 
        /* This rev is really old, and requires untested workarounds */
        if (hw->chip_id == CHIP_ID_YUKON_EC && hw->chip_rev == CHIP_REV_YU_EC_A1) {
-               printk(KERN_ERR PFX "%s: unsupported revision Yukon-%s (0x%x) rev %d\n",
-                      pci_name(hw->pdev), yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
-                      hw->chip_id, hw->chip_rev);
+               dev_err(&hw->pdev->dev, "unsupported revision Yukon-%s (0x%x) rev %d\n",
+                       yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
+                       hw->chip_id, hw->chip_rev);
                return -EOPNOTSUPP;
        }
 
+       hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
+       hw->ports = 1;
+       t8 = sky2_read8(hw, B2_Y2_HW_RES);
+       if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
+               if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC))
+                       ++hw->ports;
+       }
+
+       return 0;
+}
+
+static void sky2_reset(struct sky2_hw *hw)
+{
+       u16 status;
+       int i;
+
        /* disable ASF */
        if (hw->chip_id <= CHIP_ID_YUKON_EC) {
-               sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
+               if (hw->chip_id == CHIP_ID_YUKON_EX) {
+                       status = sky2_read16(hw, HCU_CCSR);
+                       status &= ~(HCU_CCSR_AHB_RST | HCU_CCSR_CPU_RST_MODE |
+                                   HCU_CCSR_UC_STATE_MSK);
+                       sky2_write16(hw, HCU_CCSR, status);
+               } else
+                       sky2_write8(hw, B28_Y2_ASF_STAT_CMD, Y2_ASF_RESET);
                sky2_write16(hw, B0_CTST, Y2_ASF_DISABLE);
        }
 
@@ -2472,15 +2553,7 @@ static int sky2_reset(struct sky2_hw *hw)
                sky2_pci_write32(hw, PEX_UNC_ERR_STAT, 0xffffffffUL);
 
 
-       hw->pmd_type = sky2_read8(hw, B2_PMD_TYP);
-       hw->ports = 1;
-       t8 = sky2_read8(hw, B2_Y2_HW_RES);
-       if ((t8 & CFG_DUAL_MAC_MSK) == CFG_DUAL_MAC_MSK) {
-               if (!(sky2_read8(hw, B2_Y2_CLK_GATE) & Y2_STATUS_LNK2_INAC))
-                       ++hw->ports;
-       }
-
-       sky2_set_power_state(hw, PCI_D0);
+       sky2_power_on(hw);
 
        for (i = 0; i < hw->ports; i++) {
                sky2_write8(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
@@ -2563,7 +2636,37 @@ static int sky2_reset(struct sky2_hw *hw)
        sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START);
        sky2_write8(hw, STAT_LEV_TIMER_CTRL, TIM_START);
        sky2_write8(hw, STAT_ISR_TIMER_CTRL, TIM_START);
+}
+
+static inline u8 sky2_wol_supported(const struct sky2_hw *hw)
+{
+       return sky2_is_copper(hw) ? (WAKE_PHY | WAKE_MAGIC) : 0;
+}
+
+static void sky2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       const struct sky2_port *sky2 = netdev_priv(dev);
+
+       wol->supported = sky2_wol_supported(sky2->hw);
+       wol->wolopts = sky2->wol;
+}
+
+static int sky2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct sky2_port *sky2 = netdev_priv(dev);
+       struct sky2_hw *hw = sky2->hw;
+
+       if (wol->wolopts & ~sky2_wol_supported(sky2->hw))
+               return -EOPNOTSUPP;
+
+       sky2->wol = wol->wolopts;
+
+       if (hw->chip_id == CHIP_ID_YUKON_EC_U)
+               sky2_write32(hw, B0_CTST, sky2->wol
+                            ? Y2_HW_WOL_ON : Y2_HW_WOL_OFF);
 
+       if (!netif_running(dev))
+               sky2_wol_init(sky2);
        return 0;
 }
 
@@ -2814,25 +2917,9 @@ static void sky2_get_strings(struct net_device *dev, u32 stringset, u8 * data)
        }
 }
 
-/* Use hardware MIB variables for critical path statistics and
- * transmit feedback not reported at interrupt.
- * Other errors are accounted for in interrupt handler.
- */
 static struct net_device_stats *sky2_get_stats(struct net_device *dev)
 {
        struct sky2_port *sky2 = netdev_priv(dev);
-       u64 data[13];
-
-       sky2_phy_stats(sky2, data, ARRAY_SIZE(data));
-
-       sky2->net_stats.tx_bytes = data[0];
-       sky2->net_stats.rx_bytes = data[1];
-       sky2->net_stats.tx_packets = data[2] + data[4] + data[6];
-       sky2->net_stats.rx_packets = data[3] + data[5] + data[7];
-       sky2->net_stats.multicast = data[3] + data[5];
-       sky2->net_stats.collisions = data[10];
-       sky2->net_stats.tx_aborted_errors = data[12];
-
        return &sky2->net_stats;
 }
 
@@ -3191,7 +3278,9 @@ static void sky2_get_regs(struct net_device *dev, struct ethtool_regs *regs,
 static const struct ethtool_ops sky2_ethtool_ops = {
        .get_settings = sky2_get_settings,
        .set_settings = sky2_set_settings,
-       .get_drvinfo = sky2_get_drvinfo,
+       .get_drvinfo  = sky2_get_drvinfo,
+       .get_wol      = sky2_get_wol,
+       .set_wol      = sky2_set_wol,
        .get_msglevel = sky2_get_msglevel,
        .set_msglevel = sky2_set_msglevel,
        .nway_reset   = sky2_nway_reset,
@@ -3221,13 +3310,14 @@ static const struct ethtool_ops sky2_ethtool_ops = {
 
 /* Initialize network device */
 static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
-                                                    unsigned port, int highmem)
+                                                    unsigned port,
+                                                    int highmem, int wol)
 {
        struct sky2_port *sky2;
        struct net_device *dev = alloc_etherdev(sizeof(*sky2));
 
        if (!dev) {
-               printk(KERN_ERR "sky2 etherdev alloc failed");
+               dev_err(&hw->pdev->dev, "etherdev alloc failed");
                return NULL;
        }
 
@@ -3269,6 +3359,7 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
        sky2->speed = -1;
        sky2->advertising = sky2_supported_modes(hw);
        sky2->rx_csum = 1;
+       sky2->wol = wol;
 
        spin_lock_init(&sky2->phy_lock);
        sky2->tx_pending = TX_DEF_PENDING;
@@ -3278,11 +3369,9 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw,
 
        sky2->port = port;
 
-       if (hw->chip_id != CHIP_ID_YUKON_EC_U)
-               dev->features |= NETIF_F_TSO;
+       dev->features |= NETIF_F_TSO | NETIF_F_IP_CSUM | NETIF_F_SG;
        if (highmem)
                dev->features |= NETIF_F_HIGHDMA;
-       dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
 
 #ifdef SKY2_VLAN_TAG_USED
        dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
@@ -3343,8 +3432,7 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
 
        err = request_irq(pdev->irq, sky2_test_intr, 0, DRV_NAME, hw);
        if (err) {
-               printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
-                      pci_name(pdev), pdev->irq);
+               dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
                return err;
        }
 
@@ -3355,9 +3443,8 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
 
        if (!hw->msi) {
                /* MSI test failed, go back to INTx mode */
-               printk(KERN_INFO PFX "%s: No interrupt generated using MSI, "
-                      "switching to INTx mode.\n",
-                      pci_name(pdev));
+               dev_info(&pdev->dev, "No interrupt generated using MSI, "
+                        "switching to INTx mode.\n");
 
                err = -EOPNOTSUPP;
                sky2_write8(hw, B0_CTST, CS_CL_SW_IRQ);
@@ -3371,62 +3458,62 @@ static int __devinit sky2_test_msi(struct sky2_hw *hw)
        return err;
 }
 
+static int __devinit pci_wake_enabled(struct pci_dev *dev)
+{
+       int pm  = pci_find_capability(dev, PCI_CAP_ID_PM);
+       u16 value;
+
+       if (!pm)
+               return 0;
+       if (pci_read_config_word(dev, pm + PCI_PM_CTRL, &value))
+               return 0;
+       return value & PCI_PM_CTRL_PME_ENABLE;
+}
+
 static int __devinit sky2_probe(struct pci_dev *pdev,
                                const struct pci_device_id *ent)
 {
-       struct net_device *dev, *dev1 = NULL;
+       struct net_device *dev;
        struct sky2_hw *hw;
-       int err, pm_cap, using_dac = 0;
+       int err, using_dac = 0, wol_default;
 
        err = pci_enable_device(pdev);
        if (err) {
-               printk(KERN_ERR PFX "%s cannot enable PCI device\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "cannot enable PCI device\n");
                goto err_out;
        }
 
        err = pci_request_regions(pdev, DRV_NAME);
        if (err) {
-               printk(KERN_ERR PFX "%s cannot obtain PCI resources\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "cannot obtain PCI resources\n");
                goto err_out;
        }
 
        pci_set_master(pdev);
 
-       /* Find power-management capability. */
-       pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
-       if (pm_cap == 0) {
-               printk(KERN_ERR PFX "Cannot find PowerManagement capability, "
-                      "aborting.\n");
-               err = -EIO;
-               goto err_out_free_regions;
-       }
-
        if (sizeof(dma_addr_t) > sizeof(u32) &&
            !(err = pci_set_dma_mask(pdev, DMA_64BIT_MASK))) {
                using_dac = 1;
                err = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
                if (err < 0) {
-                       printk(KERN_ERR PFX "%s unable to obtain 64 bit DMA "
-                              "for consistent allocations\n", pci_name(pdev));
+                       dev_err(&pdev->dev, "unable to obtain 64 bit DMA "
+                               "for consistent allocations\n");
                        goto err_out_free_regions;
                }
-
        } else {
                err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
                if (err) {
-                       printk(KERN_ERR PFX "%s no usable DMA configuration\n",
-                              pci_name(pdev));
+                       dev_err(&pdev->dev, "no usable DMA configuration\n");
                        goto err_out_free_regions;
                }
        }
 
+       wol_default = pci_wake_enabled(pdev) ? WAKE_MAGIC : 0;
+
        err = -ENOMEM;
        hw = kzalloc(sizeof(*hw), GFP_KERNEL);
        if (!hw) {
-               printk(KERN_ERR PFX "%s: cannot allocate hardware struct\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "cannot allocate hardware struct\n");
                goto err_out_free_regions;
        }
 
@@ -3434,11 +3521,9 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
 
        hw->regs = ioremap_nocache(pci_resource_start(pdev, 0), 0x4000);
        if (!hw->regs) {
-               printk(KERN_ERR PFX "%s: cannot map device registers\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "cannot map device registers\n");
                goto err_out_free_hw;
        }
-       hw->pm_cap = pm_cap;
 
 #ifdef __BIG_ENDIAN
        /* The sk98lin vendor driver uses hardware byte swapping but
@@ -3458,18 +3543,22 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
        if (!hw->st_le)
                goto err_out_iounmap;
 
-       err = sky2_reset(hw);
+       err = sky2_init(hw);
        if (err)
                goto err_out_iounmap;
 
-       printk(KERN_INFO PFX "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
+       dev_info(&pdev->dev, "v%s addr 0x%llx irq %d Yukon-%s (0x%x) rev %d\n",
               DRV_VERSION, (unsigned long long)pci_resource_start(pdev, 0),
               pdev->irq, yukon2_name[hw->chip_id - CHIP_ID_YUKON_XL],
               hw->chip_id, hw->chip_rev);
 
-       dev = sky2_init_netdev(hw, 0, using_dac);
-       if (!dev)
+       sky2_reset(hw);
+
+       dev = sky2_init_netdev(hw, 0, using_dac, wol_default);
+       if (!dev) {
+               err = -ENOMEM;
                goto err_out_free_pci;
+       }
 
        if (!disable_msi && pci_enable_msi(pdev) == 0) {
                err = sky2_test_msi(hw);
@@ -3481,32 +3570,33 @@ static int __devinit sky2_probe(struct pci_dev *pdev,
 
        err = register_netdev(dev);
        if (err) {
-               printk(KERN_ERR PFX "%s: cannot register net device\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "cannot register net device\n");
                goto err_out_free_netdev;
        }
 
        err = request_irq(pdev->irq,  sky2_intr, hw->msi ? 0 : IRQF_SHARED,
                          dev->name, hw);
        if (err) {
-               printk(KERN_ERR PFX "%s: cannot assign irq %d\n",
-                      pci_name(pdev), pdev->irq);
+               dev_err(&pdev->dev, "cannot assign irq %d\n", pdev->irq);
                goto err_out_unregister;
        }
        sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
 
        sky2_show_addr(dev);
 
-       if (hw->ports > 1 && (dev1 = sky2_init_netdev(hw, 1, using_dac))) {
-               if (register_netdev(dev1) == 0)
-                       sky2_show_addr(dev1);
-               else {
-                       /* Failure to register second port need not be fatal */
-                       printk(KERN_WARNING PFX
-                              "register of second port failed\n");
+       if (hw->ports > 1) {
+               struct net_device *dev1;
+
+               dev1 = sky2_init_netdev(hw, 1, using_dac, wol_default);
+               if (!dev1)
+                       dev_warn(&pdev->dev, "allocation for second device failed\n");
+               else if ((err = register_netdev(dev1))) {
+                       dev_warn(&pdev->dev,
+                                "register of second port failed (%d)\n", err);
                        hw->dev[1] = NULL;
                        free_netdev(dev1);
-               }
+               } else
+                       sky2_show_addr(dev1);
        }
 
        setup_timer(&hw->idle_timer, sky2_idle, (unsigned long) hw);
@@ -3555,7 +3645,8 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
                unregister_netdev(dev1);
        unregister_netdev(dev0);
 
-       sky2_set_power_state(hw, PCI_D3hot);
+       sky2_power_aux(hw);
+
        sky2_write16(hw, B0_Y2LED, LED_STAT_OFF);
        sky2_write8(hw, B0_CTST, CS_RST_SET);
        sky2_read8(hw, B0_CTST);
@@ -3580,27 +3671,31 @@ static void __devexit sky2_remove(struct pci_dev *pdev)
 static int sky2_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct sky2_hw *hw = pci_get_drvdata(pdev);
-       int i;
-       pci_power_t pstate = pci_choose_state(pdev, state);
-
-       if (!(pstate == PCI_D3hot || pstate == PCI_D3cold))
-               return -EINVAL;
+       int i, wol = 0;
 
        del_timer_sync(&hw->idle_timer);
        netif_poll_disable(hw->dev[0]);
 
        for (i = 0; i < hw->ports; i++) {
                struct net_device *dev = hw->dev[i];
+               struct sky2_port *sky2 = netdev_priv(dev);
 
-               if (netif_running(dev)) {
+               if (netif_running(dev))
                        sky2_down(dev);
-                       netif_device_detach(dev);
-               }
+
+               if (sky2->wol)
+                       sky2_wol_init(sky2);
+
+               wol |= sky2->wol;
        }
 
        sky2_write32(hw, B0_IMSK, 0);
+       sky2_power_aux(hw);
+
        pci_save_state(pdev);
-       sky2_set_power_state(hw, pstate);
+       pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
        return 0;
 }
 
@@ -3609,21 +3704,22 @@ static int sky2_resume(struct pci_dev *pdev)
        struct sky2_hw *hw = pci_get_drvdata(pdev);
        int i, err;
 
-       pci_restore_state(pdev);
-       pci_enable_wake(pdev, PCI_D0, 0);
-       sky2_set_power_state(hw, PCI_D0);
+       err = pci_set_power_state(pdev, PCI_D0);
+       if (err)
+               goto out;
 
-       err = sky2_reset(hw);
+       err = pci_restore_state(pdev);
        if (err)
                goto out;
 
+       pci_enable_wake(pdev, PCI_D0, 0);
+       sky2_reset(hw);
+
        sky2_write32(hw, B0_IMSK, Y2_IS_BASE);
 
        for (i = 0; i < hw->ports; i++) {
                struct net_device *dev = hw->dev[i];
                if (netif_running(dev)) {
-                       netif_device_attach(dev);
-
                        err = sky2_up(dev);
                        if (err) {
                                printk(KERN_ERR PFX "%s: could not up: %d\n",
@@ -3636,11 +3732,43 @@ static int sky2_resume(struct pci_dev *pdev)
 
        netif_poll_enable(hw->dev[0]);
        sky2_idle_start(hw);
+       return 0;
 out:
+       dev_err(&pdev->dev, "resume failed (%d)\n", err);
+       pci_disable_device(pdev);
        return err;
 }
 #endif
 
+static void sky2_shutdown(struct pci_dev *pdev)
+{
+       struct sky2_hw *hw = pci_get_drvdata(pdev);
+       int i, wol = 0;
+
+       del_timer_sync(&hw->idle_timer);
+       netif_poll_disable(hw->dev[0]);
+
+       for (i = 0; i < hw->ports; i++) {
+               struct net_device *dev = hw->dev[i];
+               struct sky2_port *sky2 = netdev_priv(dev);
+
+               if (sky2->wol) {
+                       wol = 1;
+                       sky2_wol_init(sky2);
+               }
+       }
+
+       if (wol)
+               sky2_power_aux(hw);
+
+       pci_enable_wake(pdev, PCI_D3hot, wol);
+       pci_enable_wake(pdev, PCI_D3cold, wol);
+
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, PCI_D3hot);
+
+}
+
 static struct pci_driver sky2_driver = {
        .name = DRV_NAME,
        .id_table = sky2_id_table,
@@ -3650,6 +3778,7 @@ static struct pci_driver sky2_driver = {
        .suspend = sky2_suspend,
        .resume = sky2_resume,
 #endif
+       .shutdown = sky2_shutdown,
 };
 
 static int __init sky2_init_module(void)
index 6ed1d47..3b01895 100644 (file)
@@ -32,6 +32,7 @@ enum pci_dev_reg_1 {
        PCI_Y2_PHY1_COMA = 1<<28, /* Set PHY 1 to Coma Mode (YUKON-2) */
        PCI_Y2_PHY2_POWD = 1<<27, /* Set PHY 2 to Power Down (YUKON-2) */
        PCI_Y2_PHY1_POWD = 1<<26, /* Set PHY 1 to Power Down (YUKON-2) */
+       PCI_Y2_PME_LEGACY= 1<<15, /* PCI Express legacy power management mode */
 };
 
 enum pci_dev_reg_2 {
@@ -370,12 +371,9 @@ enum {
 
 /*     B2_CHIP_ID               8 bit  Chip Identification Number */
 enum {
-       CHIP_ID_GENESIS    = 0x0a, /* Chip ID for GENESIS */
-       CHIP_ID_YUKON      = 0xb0, /* Chip ID for YUKON */
-       CHIP_ID_YUKON_LITE = 0xb1, /* Chip ID for YUKON-Lite (Rev. A1-A3) */
-       CHIP_ID_YUKON_LP   = 0xb2, /* Chip ID for YUKON-LP */
        CHIP_ID_YUKON_XL   = 0xb3, /* Chip ID for YUKON-2 XL */
        CHIP_ID_YUKON_EC_U = 0xb4, /* Chip ID for YUKON-2 EC Ultra */
+       CHIP_ID_YUKON_EX   = 0xb5, /* Chip ID for YUKON-2 Extreme */
        CHIP_ID_YUKON_EC   = 0xb6, /* Chip ID for YUKON-2 EC */
        CHIP_ID_YUKON_FE   = 0xb7, /* Chip ID for YUKON-2 FE */
 
@@ -767,6 +765,24 @@ enum {
        POLL_LIST_ADDR_HI= 0x0e2c,/* 32 bit     Poll. List Start Addr (high) */
 };
 
+enum {
+       SMB_CFG          = 0x0e40, /* 32 bit    SMBus Config Register */
+       SMB_CSR          = 0x0e44, /* 32 bit    SMBus Control/Status Register */
+};
+
+enum {
+       CPU_WDOG         = 0x0e48, /* 32 bit    Watchdog Register  */
+       CPU_CNTR         = 0x0e4C, /* 32 bit    Counter Register  */
+       CPU_TIM          = 0x0e50,/* 32 bit     Timer Compare Register  */
+       CPU_AHB_ADDR     = 0x0e54, /* 32 bit    CPU AHB Debug  Register  */
+       CPU_AHB_WDATA    = 0x0e58, /* 32 bit    CPU AHB Debug  Register  */
+       CPU_AHB_RDATA    = 0x0e5C, /* 32 bit    CPU AHB Debug  Register  */
+       HCU_MAP_BASE     = 0x0e60, /* 32 bit    Reset Mapping Base */
+       CPU_AHB_CTRL     = 0x0e64, /* 32 bit    CPU AHB Debug  Register  */
+       HCU_CCSR         = 0x0e68, /* 32 bit    CPU Control and Status Register */
+       HCU_HCSR         = 0x0e6C, /* 32 bit    Host Control and Status Register */
+};
+
 /* ASF Subsystem Registers (Yukon-2 only) */
 enum {
        B28_Y2_SMB_CONFIG  = 0x0e40,/* 32 bit   ASF SMBus Config Register */
@@ -837,33 +853,27 @@ enum {
        GMAC_LINK_CTRL  = 0x0f10,/* 16 bit      Link Control Reg */
 
 /* Wake-up Frame Pattern Match Control Registers (YUKON only) */
-
-       WOL_REG_OFFS    = 0x20,/* HW-Bug: Address is + 0x20 against spec. */
-
        WOL_CTRL_STAT   = 0x0f20,/* 16 bit      WOL Control/Status Reg */
        WOL_MATCH_CTL   = 0x0f22,/*  8 bit      WOL Match Control Reg */
        WOL_MATCH_RES   = 0x0f23,/*  8 bit      WOL Match Result Reg */
        WOL_MAC_ADDR    = 0x0f24,/* 32 bit      WOL MAC Address */
-       WOL_PATT_PME    = 0x0f2a,/*  8 bit      WOL PME Match Enable (Yukon-2) */
-       WOL_PATT_ASFM   = 0x0f2b,/*  8 bit      WOL ASF Match Enable (Yukon-2) */
        WOL_PATT_RPTR   = 0x0f2c,/*  8 bit      WOL Pattern Read Pointer */
 
 /* WOL Pattern Length Registers (YUKON only) */
-
        WOL_PATT_LEN_LO = 0x0f30,/* 32 bit      WOL Pattern Length 3..0 */
        WOL_PATT_LEN_HI = 0x0f34,/* 24 bit      WOL Pattern Length 6..4 */
 
 /* WOL Pattern Counter Registers (YUKON only) */
-
-
        WOL_PATT_CNT_0  = 0x0f38,/* 32 bit      WOL Pattern Counter 3..0 */
        WOL_PATT_CNT_4  = 0x0f3c,/* 24 bit      WOL Pattern Counter 6..4 */
 };
+#define WOL_REGS(port, x)      (x + (port)*0x80)
 
 enum {
        WOL_PATT_RAM_1  = 0x1000,/*  WOL Pattern RAM Link 1 */
        WOL_PATT_RAM_2  = 0x1400,/*  WOL Pattern RAM Link 2 */
 };
+#define WOL_PATT_RAM_BASE(port)        (WOL_PATT_RAM_1 + (port)*0x400)
 
 enum {
        BASE_GMAC_1     = 0x2800,/* GMAC 1 registers */
@@ -1654,6 +1664,39 @@ enum {
        Y2_ASF_CLR_ASFI = 1<<1, /* Clear host IRQ */
        Y2_ASF_HOST_IRQ = 1<<0, /* Issue an IRQ to HOST system */
 };
+/*     HCU_CCSR        CPU Control and Status Register */
+enum {
+       HCU_CCSR_SMBALERT_MONITOR= 1<<27, /* SMBALERT pin monitor */
+       HCU_CCSR_CPU_SLEEP      = 1<<26, /* CPU sleep status */
+       /* Clock Stretching Timeout */
+       HCU_CCSR_CS_TO          = 1<<25,
+       HCU_CCSR_WDOG           = 1<<24, /* Watchdog Reset */
+
+       HCU_CCSR_CLR_IRQ_HOST   = 1<<17, /* Clear IRQ_HOST */
+       HCU_CCSR_SET_IRQ_HCU    = 1<<16, /* Set IRQ_HCU */
+
+       HCU_CCSR_AHB_RST        = 1<<9, /* Reset AHB bridge */
+       HCU_CCSR_CPU_RST_MODE   = 1<<8, /* CPU Reset Mode */
+
+       HCU_CCSR_SET_SYNC_CPU   = 1<<5,
+       HCU_CCSR_CPU_CLK_DIVIDE_MSK = 3<<3,/* CPU Clock Divide */
+       HCU_CCSR_CPU_CLK_DIVIDE_BASE= 1<<3,
+       HCU_CCSR_OS_PRSNT       = 1<<2, /* ASF OS Present */
+/* Microcontroller State */
+       HCU_CCSR_UC_STATE_MSK   = 3,
+       HCU_CCSR_UC_STATE_BASE  = 1<<0,
+       HCU_CCSR_ASF_RESET      = 0,
+       HCU_CCSR_ASF_HALTED     = 1<<1,
+       HCU_CCSR_ASF_RUNNING    = 1<<0,
+};
+
+/*     HCU_HCSR        Host Control and Status Register */
+enum {
+       HCU_HCSR_SET_IRQ_CPU    = 1<<16, /* Set IRQ_CPU */
+
+       HCU_HCSR_CLR_IRQ_HCU    = 1<<1, /* Clear IRQ_HCU */
+       HCU_HCSR_SET_IRQ_HOST   = 1<<0, /* Set IRQ_HOST */
+};
 
 /*     STAT_CTRL               32 bit  Status BMU control register (Yukon-2 only) */
 enum {
@@ -1715,14 +1758,17 @@ enum {
        GM_IS_RX_COMPL  = 1<<0, /* Frame Reception Complete */
 
 #define GMAC_DEF_MSK     GM_IS_TX_FF_UR
+};
 
 /*     GMAC_LINK_CTRL  16 bit  GMAC Link Control Reg (YUKON only) */
-                                               /* Bits 15.. 2: reserved */
+enum {                                         /* Bits 15.. 2: reserved */
        GMLC_RST_CLR    = 1<<1, /* Clear GMAC Link Reset */
        GMLC_RST_SET    = 1<<0, /* Set   GMAC Link Reset */
+};
 
 
 /*     WOL_CTRL_STAT   16 bit  WOL Control/Status Reg */
+enum {
        WOL_CTL_LINK_CHG_OCC            = 1<<15,
        WOL_CTL_MAGIC_PKT_OCC           = 1<<14,
        WOL_CTL_PATTERN_OCC             = 1<<13,
@@ -1741,17 +1787,6 @@ enum {
        WOL_CTL_DIS_PATTERN_UNIT        = 1<<0,
 };
 
-#define WOL_CTL_DEFAULT                                \
-       (WOL_CTL_DIS_PME_ON_LINK_CHG |  \
-       WOL_CTL_DIS_PME_ON_PATTERN |    \
-       WOL_CTL_DIS_PME_ON_MAGIC_PKT |  \
-       WOL_CTL_DIS_LINK_CHG_UNIT |             \
-       WOL_CTL_DIS_PATTERN_UNIT |              \
-       WOL_CTL_DIS_MAGIC_PKT_UNIT)
-
-/*     WOL_MATCH_CTL    8 bit  WOL Match Control Reg */
-#define WOL_CTL_PATT_ENA(x)    (1 << (x))
-
 
 /* Control flags */
 enum {
@@ -1875,6 +1910,7 @@ struct sky2_port {
        u8                   autoneg;   /* AUTONEG_ENABLE, AUTONEG_DISABLE */
        u8                   duplex;    /* DUPLEX_HALF, DUPLEX_FULL */
        u8                   rx_csum;
+       u8                   wol;
        enum flow_control    flow_mode;
        enum flow_control    flow_status;
 
@@ -1887,7 +1923,6 @@ struct sky2_hw {
        struct pci_dev       *pdev;
        struct net_device    *dev[2];
 
-       int                  pm_cap;
        u8                   chip_id;
        u8                   chip_rev;
        u8                   pmd_type;
index 43af614..c956141 100644 (file)
@@ -1659,7 +1659,7 @@ smc911x_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        strncpy(info->driver, CARDNAME, sizeof(info->driver));
        strncpy(info->version, version, sizeof(info->version));
-       strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+       strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
 }
 
 static int smc911x_ethtool_nwayreset(struct net_device *dev)
index e62a958..49f4b77 100644 (file)
@@ -1712,7 +1712,7 @@ smc_ethtool_getdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
        strncpy(info->driver, CARDNAME, sizeof(info->driver));
        strncpy(info->version, version, sizeof(info->version));
-       strncpy(info->bus_info, dev->class_dev.dev->bus_id, sizeof(info->bus_info));
+       strncpy(info->bus_info, dev->dev.parent->bus_id, sizeof(info->bus_info));
 }
 
 static int smc_ethtool_nwayreset(struct net_device *dev)
index 8ea2fc1..bf6ff39 100644 (file)
@@ -280,72 +280,67 @@ spider_net_free_chain(struct spider_net_card *card,
 {
        struct spider_net_descr *descr;
 
-       for (descr = chain->tail; !descr->bus_addr; descr = descr->next) {
-               pci_unmap_single(card->pdev, descr->bus_addr,
-                                SPIDER_NET_DESCR_SIZE, PCI_DMA_BIDIRECTIONAL);
+       descr = chain->ring;
+       do {
                descr->bus_addr = 0;
-       }
+               descr->next_descr_addr = 0;
+               descr = descr->next;
+       } while (descr != chain->ring);
+
+       dma_free_coherent(&card->pdev->dev, chain->num_desc,
+           chain->ring, chain->dma_addr);
 }
 
 /**
- * spider_net_init_chain - links descriptor chain
+ * spider_net_init_chain - alloc and link descriptor chain
  * @card: card structure
  * @chain: address of chain
- * @start_descr: address of descriptor array
- * @no: number of descriptors
  *
- * we manage a circular list that mirrors the hardware structure,
+ * We manage a circular list that mirrors the hardware structure,
  * except that the hardware uses bus addresses.
  *
- * returns 0 on success, <0 on failure
+ * Returns 0 on success, <0 on failure
  */
 static int
 spider_net_init_chain(struct spider_net_card *card,
-                      struct spider_net_descr_chain *chain,
-                      struct spider_net_descr *start_descr,
-                      int no)
+                      struct spider_net_descr_chain *chain)
 {
        int i;
        struct spider_net_descr *descr;
        dma_addr_t buf;
+       size_t alloc_size;
 
-       descr = start_descr;
-       memset(descr, 0, sizeof(*descr) * no);
+       alloc_size = chain->num_desc * sizeof (struct spider_net_descr);
 
-       /* set up the hardware pointers in each descriptor */
-       for (i=0; i<no; i++, descr++) {
-               descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+       chain->ring = dma_alloc_coherent(&card->pdev->dev, alloc_size,
+               &chain->dma_addr, GFP_KERNEL);
+
+       if (!chain->ring)
+               return -ENOMEM;
 
-               buf = pci_map_single(card->pdev, descr,
-                                    SPIDER_NET_DESCR_SIZE,
-                                    PCI_DMA_BIDIRECTIONAL);
+       descr = chain->ring;
+       memset(descr, 0, alloc_size);
 
-               if (pci_dma_mapping_error(buf))
-                       goto iommu_error;
+       /* Set up the hardware pointers in each descriptor */
+       buf = chain->dma_addr;
+       for (i=0; i < chain->num_desc; i++, descr++) {
+               descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
 
                descr->bus_addr = buf;
+               descr->next_descr_addr = 0;
                descr->next = descr + 1;
                descr->prev = descr - 1;
 
+               buf += sizeof(struct spider_net_descr);
        }
        /* do actual circular list */
-       (descr-1)->next = start_descr;
-       start_descr->prev = descr-1;
+       (descr-1)->next = chain->ring;
+       chain->ring->prev = descr-1;
 
        spin_lock_init(&chain->lock);
-       chain->head = start_descr;
-       chain->tail = start_descr;
-
+       chain->head = chain->ring;
+       chain->tail = chain->ring;
        return 0;
-
-iommu_error:
-       descr = start_descr;
-       for (i=0; i < no; i++, descr++)
-               if (descr->bus_addr)
-                       pci_unmap_single(card->pdev, descr->bus_addr,
-                                        SPIDER_NET_DESCR_SIZE,
-                                        PCI_DMA_BIDIRECTIONAL);
-       return -ENOMEM;
 }
 
 /**
@@ -372,21 +367,20 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card)
 }
 
 /**
- * spider_net_prepare_rx_descr - reinitializes a rx descriptor
+ * spider_net_prepare_rx_descr - Reinitialize RX descriptor
  * @card: card structure
  * @descr: descriptor to re-init
  *
- * return 0 on succes, <0 on failure
+ * Return 0 on succes, <0 on failure.
  *
- * allocates a new rx skb, iommu-maps it and attaches it to the descriptor.
- * Activate the descriptor state-wise
+ * Allocates a new rx skb, iommu-maps it and attaches it to the
+ * descriptor. Mark the descriptor as activated, ready-to-use.
  */
 static int
 spider_net_prepare_rx_descr(struct spider_net_card *card,
                            struct spider_net_descr *descr)
 {
        dma_addr_t buf;
-       int error = 0;
        int offset;
        int bufsize;
 
@@ -414,7 +408,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
                (SPIDER_NET_RXBUF_ALIGN - 1);
        if (offset)
                skb_reserve(descr->skb, SPIDER_NET_RXBUF_ALIGN - offset);
-       /* io-mmu-map the skb */
+       /* iommu-map the skb */
        buf = pci_map_single(card->pdev, descr->skb->data,
                        SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
        descr->buf_addr = buf;
@@ -425,11 +419,16 @@ spider_net_prepare_rx_descr(struct spider_net_card *card,
                card->spider_stats.rx_iommu_map_error++;
                descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
        } else {
+               descr->next_descr_addr = 0;
+               wmb();
                descr->dmac_cmd_status = SPIDER_NET_DESCR_CARDOWNED |
                                         SPIDER_NET_DMAC_NOINTR_COMPLETE;
+
+               wmb();
+               descr->prev->next_descr_addr = descr->bus_addr;
        }
 
-       return error;
+       return 0;
 }
 
 /**
@@ -493,10 +492,10 @@ spider_net_refill_rx_chain(struct spider_net_card *card)
 }
 
 /**
- * spider_net_alloc_rx_skbs - allocates rx skbs in rx descriptor chains
+ * spider_net_alloc_rx_skbs - Allocates rx skbs in rx descriptor chains
  * @card: card structure
  *
- * returns 0 on success, <0 on failure
+ * Returns 0 on success, <0 on failure.
  */
 static int
 spider_net_alloc_rx_skbs(struct spider_net_card *card)
@@ -507,16 +506,16 @@ spider_net_alloc_rx_skbs(struct spider_net_card *card)
        result = -ENOMEM;
 
        chain = &card->rx_chain;
-       /* put at least one buffer into the chain. if this fails,
-        * we've got a problem. if not, spider_net_refill_rx_chain
-        * will do the rest at the end of this function */
+       /* Put at least one buffer into the chain. if this fails,
+        * we've got a problem. If not, spider_net_refill_rx_chain
+        * will do the rest at the end of this function. */
        if (spider_net_prepare_rx_descr(card, chain->head))
                goto error;
        else
                chain->head = chain->head->next;
 
-       /* this will allocate the rest of the rx buffers; if not, it's
-        * business as usual later on */
+       /* This will allocate the rest of the rx buffers;
+        * if not, it's business as usual later on. */
        spider_net_refill_rx_chain(card);
        spider_net_enable_rxdmac(card);
        return 0;
@@ -707,7 +706,7 @@ spider_net_set_low_watermark(struct spider_net_card *card)
        }
 
        /* If TX queue is short, don't even bother with interrupts */
-       if (cnt < card->num_tx_desc/4)
+       if (cnt < card->tx_chain.num_desc/4)
                return cnt;
 
        /* Set low-watermark 3/4th's of the way into the queue. */
@@ -915,16 +914,13 @@ spider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
  * spider_net_pass_skb_up - takes an skb from a descriptor and passes it on
  * @descr: descriptor to process
  * @card: card structure
- * @napi: whether caller is in NAPI context
- *
- * returns 1 on success, 0 if no packet was passed to the stack
  *
- * iommu-unmaps the skb, fills out skb structure and passes the data to the
- * stack. The descriptor state is not changed.
+ * Fills out skb structure and passes the data to the stack.
+ * The descriptor state is not changed.
  */
-static int
+static void
 spider_net_pass_skb_up(struct spider_net_descr *descr,
-                      struct spider_net_card *card, int napi)
+                      struct spider_net_card *card)
 {
        struct sk_buff *skb;
        struct net_device *netdev;
@@ -932,23 +928,8 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
 
        data_status = descr->data_status;
        data_error = descr->data_error;
-
        netdev = card->netdev;
 
-       /* unmap descriptor */
-       pci_unmap_single(card->pdev, descr->buf_addr, SPIDER_NET_MAX_FRAME,
-                       PCI_DMA_FROMDEVICE);
-
-       /* the cases we'll throw away the packet immediately */
-       if (data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
-               if (netif_msg_rx_err(card))
-                       pr_err("error in received descriptor found, "
-                              "data_status=x%08x, data_error=x%08x\n",
-                              data_status, data_error);
-               card->spider_stats.rx_desc_error++;
-               return 0;
-       }
-
        skb = descr->skb;
        skb->dev = netdev;
        skb_put(skb, descr->valid_size);
@@ -977,57 +958,72 @@ spider_net_pass_skb_up(struct spider_net_descr *descr,
        }
 
        /* pass skb up to stack */
-       if (napi)
-               netif_receive_skb(skb);
-       else
-               netif_rx_ni(skb);
+       netif_receive_skb(skb);
 
        /* update netdevice statistics */
        card->netdev_stats.rx_packets++;
        card->netdev_stats.rx_bytes += skb->len;
+}
 
-       return 1;
+#ifdef DEBUG
+static void show_rx_chain(struct spider_net_card *card)
+{
+       struct spider_net_descr_chain *chain = &card->rx_chain;
+       struct spider_net_descr *start= chain->tail;
+       struct spider_net_descr *descr= start;
+       int status;
+
+       int cnt = 0;
+       int cstat = spider_net_get_descr_status(descr);
+       printk(KERN_INFO "RX chain tail at descr=%ld\n",
+            (start - card->descr) - card->tx_chain.num_desc);
+       status = cstat;
+       do
+       {
+               status = spider_net_get_descr_status(descr);
+               if (cstat != status) {
+                       printk(KERN_INFO "Have %d descrs with stat=x%08x\n", cnt, cstat);
+                       cstat = status;
+                       cnt = 0;
+               }
+               cnt ++;
+               descr = descr->next;
+       } while (descr != start);
+       printk(KERN_INFO "Last %d descrs with stat=x%08x\n", cnt, cstat);
 }
+#endif
 
 /**
  * spider_net_decode_one_descr - processes an rx descriptor
  * @card: card structure
- * @napi: whether caller is in NAPI context
  *
- * returns 1 if a packet has been sent to the stack, otherwise 0
+ * Returns 1 if a packet has been sent to the stack, otherwise 0
  *
- * processes an rx descriptor by iommu-unmapping the data buffer and passing
+ * Processes an rx descriptor by iommu-unmapping the data buffer and passing
  * the packet up to the stack. This function is called in softirq
  * context, e.g. either bottom half from interrupt or NAPI polling context
  */
 static int
-spider_net_decode_one_descr(struct spider_net_card *card, int napi)
+spider_net_decode_one_descr(struct spider_net_card *card)
 {
        struct spider_net_descr_chain *chain = &card->rx_chain;
        struct spider_net_descr *descr = chain->tail;
        int status;
-       int result;
 
        status = spider_net_get_descr_status(descr);
 
-       if (status == SPIDER_NET_DESCR_CARDOWNED) {
-               /* nothing in the descriptor yet */
-               result=0;
-               goto out;
-       }
-
-       if (status == SPIDER_NET_DESCR_NOT_IN_USE) {
-               /* not initialized yet, the ring must be empty */
-               spider_net_refill_rx_chain(card);
-               spider_net_enable_rxdmac(card);
-               result=0;
-               goto out;
-       }
+       /* Nothing in the descriptor, or ring must be empty */
+       if ((status == SPIDER_NET_DESCR_CARDOWNED) ||
+           (status == SPIDER_NET_DESCR_NOT_IN_USE))
+               return 0;
 
        /* descriptor definitively used -- move on tail */
        chain->tail = descr->next;
 
-       result = 0;
+       /* unmap descriptor */
+       pci_unmap_single(card->pdev, descr->buf_addr,
+                       SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
+
        if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||
             (status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||
             (status == SPIDER_NET_DESCR_FORCE_END) ) {
@@ -1035,31 +1031,55 @@ spider_net_decode_one_descr(struct spider_net_card *card, int napi)
                        pr_err("%s: dropping RX descriptor with state %d\n",
                               card->netdev->name, status);
                card->netdev_stats.rx_dropped++;
-               pci_unmap_single(card->pdev, descr->buf_addr,
-                               SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);
-               dev_kfree_skb_irq(descr->skb);
-               goto refill;
+               goto bad_desc;
        }
 
        if ( (status != SPIDER_NET_DESCR_COMPLETE) &&
             (status != SPIDER_NET_DESCR_FRAME_END) ) {
-               if (netif_msg_rx_err(card)) {
-                       pr_err("%s: RX descriptor with state %d\n",
+               if (netif_msg_rx_err(card))
+                       pr_err("%s: RX descriptor with unkown state %d\n",
                               card->netdev->name, status);
-                       card->spider_stats.rx_desc_unk_state++;
-               }
-               goto refill;
+               card->spider_stats.rx_desc_unk_state++;
+               goto bad_desc;
        }
 
-       /* ok, we've got a packet in descr */
-       result = spider_net_pass_skb_up(descr, card, napi);
-refill:
+       /* The cases we'll throw away the packet immediately */
+       if (descr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {
+               if (netif_msg_rx_err(card))
+                       pr_err("%s: error in received descriptor found, "
+                              "data_status=x%08x, data_error=x%08x\n",
+                              card->netdev->name,
+                              descr->data_status, descr->data_error);
+               goto bad_desc;
+       }
+
+       if (descr->dmac_cmd_status & 0xfefe) {
+               pr_err("%s: bad status, cmd_status=x%08x\n",
+                              card->netdev->name,
+                              descr->dmac_cmd_status);
+               pr_err("buf_addr=x%08x\n", descr->buf_addr);
+               pr_err("buf_size=x%08x\n", descr->buf_size);
+               pr_err("next_descr_addr=x%08x\n", descr->next_descr_addr);
+               pr_err("result_size=x%08x\n", descr->result_size);
+               pr_err("valid_size=x%08x\n", descr->valid_size);
+               pr_err("data_status=x%08x\n", descr->data_status);
+               pr_err("data_error=x%08x\n", descr->data_error);
+               pr_err("bus_addr=x%08x\n", descr->bus_addr);
+               pr_err("which=%ld\n", descr - card->rx_chain.ring);
+
+               card->spider_stats.rx_desc_error++;
+               goto bad_desc;
+       }
+
+       /* Ok, we've got a packet in descr */
+       spider_net_pass_skb_up(descr, card);
        descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
-       /* change the descriptor state: */
-       if (!napi)
-               spider_net_refill_rx_chain(card);
-out:
-       return result;
+       return 1;
+
+bad_desc:
+       dev_kfree_skb_irq(descr->skb);
+       descr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;
+       return 0;
 }
 
 /**
@@ -1085,7 +1105,7 @@ spider_net_poll(struct net_device *netdev, int *budget)
        packets_to_do = min(*budget, netdev->quota);
 
        while (packets_to_do) {
-               if (spider_net_decode_one_descr(card, 1)) {
+               if (spider_net_decode_one_descr(card)) {
                        packets_done++;
                        packets_to_do--;
                } else {
@@ -1098,6 +1118,7 @@ spider_net_poll(struct net_device *netdev, int *budget)
        netdev->quota -= packets_done;
        *budget -= packets_done;
        spider_net_refill_rx_chain(card);
+       spider_net_enable_rxdmac(card);
 
        /* if all packets are in the stack, enable interrupts and return 0 */
        /* if not, return 1 */
@@ -1226,24 +1247,6 @@ spider_net_set_mac(struct net_device *netdev, void *p)
        return 0;
 }
 
-/**
- * spider_net_handle_rxram_full - cleans up RX ring upon RX RAM full interrupt
- * @card: card structure
- *
- * spider_net_handle_rxram_full empties the RX ring so that spider can put
- * more packets in it and empty its RX RAM. This is called in bottom half
- * context
- */
-static void
-spider_net_handle_rxram_full(struct spider_net_card *card)
-{
-       while (spider_net_decode_one_descr(card, 0))
-               ;
-       spider_net_enable_rxchtails(card);
-       spider_net_enable_rxdmac(card);
-       netif_rx_schedule(card->netdev);
-}
-
 /**
  * spider_net_handle_error_irq - handles errors raised by an interrupt
  * @card: card structure
@@ -1366,10 +1369,10 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
        case SPIDER_NET_GRFAFLLINT: /* fallthrough */
        case SPIDER_NET_GRMFLLINT:
                if (netif_msg_intr(card) && net_ratelimit())
-                       pr_debug("Spider RX RAM full, incoming packets "
+                       pr_err("Spider RX RAM full, incoming packets "
                               "might be discarded!\n");
                spider_net_rx_irq_off(card);
-               tasklet_schedule(&card->rxram_full_tl);
+               netif_rx_schedule(card->netdev);
                show_error = 0;
                break;
 
@@ -1384,7 +1387,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
        case SPIDER_NET_GDCDCEINT: /* fallthrough */
        case SPIDER_NET_GDBDCEINT: /* fallthrough */
        case SPIDER_NET_GDADCEINT:
-               if (netif_msg_intr(card))
+               if (netif_msg_intr(card) && net_ratelimit())
                        pr_err("got descriptor chain end interrupt, "
                               "restarting DMAC %c.\n",
                               'D'-(i-SPIDER_NET_GDDDCEINT)/3);
@@ -1455,7 +1458,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg)
                        break;
        }
 
-       if ((show_error) && (netif_msg_intr(card)))
+       if ((show_error) && (netif_msg_intr(card)) && net_ratelimit())
                pr_err("Got error interrupt on %s, GHIINT0STS = 0x%08x, "
                       "GHIINT1STS = 0x%08x, GHIINT2STS = 0x%08x\n",
                       card->netdev->name,
@@ -1651,27 +1654,18 @@ int
 spider_net_open(struct net_device *netdev)
 {
        struct spider_net_card *card = netdev_priv(netdev);
-       struct spider_net_descr *descr;
-       int i, result;
+       int result;
 
-       result = -ENOMEM;
-       if (spider_net_init_chain(card, &card->tx_chain, card->descr,
-                                 card->num_tx_desc))
+       result = spider_net_init_chain(card, &card->tx_chain);
+       if (result)
                goto alloc_tx_failed;
-
        card->low_watermark = NULL;
 
-       /* rx_chain is after tx_chain, so offset is descr + tx_count */
-       if (spider_net_init_chain(card, &card->rx_chain,
-                                 card->descr + card->num_tx_desc,
-                                 card->num_rx_desc))
+       result = spider_net_init_chain(card, &card->rx_chain);
+       if (result)
                goto alloc_rx_failed;
 
-       descr = card->rx_chain.head;
-       for (i=0; i < card->num_rx_desc; i++, descr++)
-               descr->next_descr_addr = descr->next->bus_addr;
-
-       /* allocate rx skbs */
+       /* Allocate rx skbs */
        if (spider_net_alloc_rx_skbs(card))
                goto alloc_skbs_failed;
 
@@ -1902,7 +1896,6 @@ spider_net_stop(struct net_device *netdev)
 {
        struct spider_net_card *card = netdev_priv(netdev);
 
-       tasklet_kill(&card->rxram_full_tl);
        netif_poll_disable(netdev);
        netif_carrier_off(netdev);
        netif_stop_queue(netdev);
@@ -1924,6 +1917,7 @@ spider_net_stop(struct net_device *netdev)
 
        /* release chains */
        spider_net_release_tx_chain(card, 1);
+       spider_net_free_rx_chain_contents(card);
 
        spider_net_free_rx_chain_contents(card);
 
@@ -2046,9 +2040,6 @@ spider_net_setup_netdev(struct spider_net_card *card)
 
        pci_set_drvdata(card->pdev, netdev);
 
-       card->rxram_full_tl.data = (unsigned long) card;
-       card->rxram_full_tl.func =
-               (void (*)(unsigned long)) spider_net_handle_rxram_full;
        init_timer(&card->tx_timer);
        card->tx_timer.function =
                (void (*)(unsigned long)) spider_net_cleanup_tx_ring;
@@ -2057,8 +2048,8 @@ spider_net_setup_netdev(struct spider_net_card *card)
 
        card->options.rx_csum = SPIDER_NET_RX_CSUM_DEFAULT;
 
-       card->num_tx_desc = tx_descriptors;
-       card->num_rx_desc = rx_descriptors;
+       card->tx_chain.num_desc = tx_descriptors;
+       card->rx_chain.num_desc = rx_descriptors;
 
        spider_net_setup_netdev_ops(netdev);
 
@@ -2107,12 +2098,8 @@ spider_net_alloc_card(void)
 {
        struct net_device *netdev;
        struct spider_net_card *card;
-       size_t alloc_size;
 
-       alloc_size = sizeof (*card) +
-               sizeof (struct spider_net_descr) * rx_descriptors +
-               sizeof (struct spider_net_descr) * tx_descriptors;
-       netdev = alloc_etherdev(alloc_size);
+       netdev = alloc_etherdev(sizeof(struct spider_net_card));
        if (!netdev)
                return NULL;
 
index 3e196df..2fec5cf 100644 (file)
@@ -24,7 +24,7 @@
 #ifndef _SPIDER_NET_H
 #define _SPIDER_NET_H
 
-#define VERSION "1.6 A"
+#define VERSION "1.6 B"
 
 #include "sungem_phy.h"
 
@@ -378,6 +378,9 @@ struct spider_net_descr_chain {
        spinlock_t lock;
        struct spider_net_descr *head;
        struct spider_net_descr *tail;
+       struct spider_net_descr *ring;
+       int num_desc;
+       dma_addr_t dma_addr;
 };
 
 /* descriptor data_status bits */
@@ -397,8 +400,6 @@ struct spider_net_descr_chain {
  * 701b8000 would be correct, but every packets gets that flag */
 #define SPIDER_NET_DESTROY_RX_FLAGS    0x700b8000
 
-#define SPIDER_NET_DESCR_SIZE          32
-
 /* this will be bigger some time */
 struct spider_net_options {
        int rx_csum; /* for rx: if 0 ip_summed=NONE,
@@ -441,25 +442,16 @@ struct spider_net_card {
        struct spider_net_descr_chain rx_chain;
        struct spider_net_descr *low_watermark;
 
-       struct net_device_stats netdev_stats;
-
-       struct spider_net_options options;
-
-       spinlock_t intmask_lock;
-       struct tasklet_struct rxram_full_tl;
        struct timer_list tx_timer;
-
        struct work_struct tx_timeout_task;
        atomic_t tx_timeout_task_counter;
        wait_queue_head_t waitq;
 
        /* for ethtool */
        int msg_enable;
-       int num_rx_desc;
-       int num_tx_desc;
+       struct net_device_stats netdev_stats;
        struct spider_net_extra_stats spider_stats;
-
-       struct spider_net_descr descr[0];
+       struct spider_net_options options;
 };
 
 #define pr_err(fmt,arg...) \
index 91b9951..6bcf03f 100644 (file)
@@ -158,9 +158,9 @@ spider_net_ethtool_get_ringparam(struct net_device *netdev,
        struct spider_net_card *card = netdev->priv;
 
        ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX;
-       ering->tx_pending = card->num_tx_desc;
+       ering->tx_pending = card->tx_chain.num_desc;
        ering->rx_max_pending = SPIDER_NET_RX_DESCRIPTORS_MAX;
-       ering->rx_pending = card->num_rx_desc;
+       ering->rx_pending = card->rx_chain.num_desc;
 }
 
 static int spider_net_get_stats_count(struct net_device *netdev)
index f4bf62c..135c098 100644 (file)
 #define TG3_VLAN_TAG_USED 0
 #endif
 
-#ifdef NETIF_F_TSO
 #define TG3_TSO_SUPPORT        1
-#else
-#define TG3_TSO_SUPPORT        0
-#endif
 
 #include "tg3.h"
 
@@ -3873,7 +3869,6 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        entry = tp->tx_prod;
        base_flags = 0;
-#if TG3_TSO_SUPPORT != 0
        mss = 0;
        if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
            (mss = skb_shinfo(skb)->gso_size) != 0) {
@@ -3906,11 +3901,6 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
        }
        else if (skb->ip_summed == CHECKSUM_PARTIAL)
                base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#else
-       mss = 0;
-       if (skb->ip_summed == CHECKSUM_PARTIAL)
-               base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#endif
 #if TG3_VLAN_TAG_USED
        if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
                base_flags |= (TXD_FLAG_VLAN |
@@ -3970,7 +3960,6 @@ out_unlock:
        return NETDEV_TX_OK;
 }
 
-#if TG3_TSO_SUPPORT != 0
 static int tg3_start_xmit_dma_bug(struct sk_buff *, struct net_device *);
 
 /* Use GSO to workaround a rare TSO bug that may be triggered when the
@@ -4002,7 +3991,6 @@ tg3_tso_bug_end:
 
        return NETDEV_TX_OK;
 }
-#endif
 
 /* hard_start_xmit for devices that have the 4G bug and/or 40-bit bug and
  * support TG3_FLG2_HW_TSO_1 or firmware TSO only.
@@ -4036,7 +4024,6 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
        base_flags = 0;
        if (skb->ip_summed == CHECKSUM_PARTIAL)
                base_flags |= TXD_FLAG_TCPUDP_CSUM;
-#if TG3_TSO_SUPPORT != 0
        mss = 0;
        if (skb->len > (tp->dev->mtu + ETH_HLEN) &&
            (mss = skb_shinfo(skb)->gso_size) != 0) {
@@ -4091,9 +4078,6 @@ static int tg3_start_xmit_dma_bug(struct sk_buff *skb, struct net_device *dev)
                        }
                }
        }
-#else
-       mss = 0;
-#endif
 #if TG3_VLAN_TAG_USED
        if (tp->vlgrp != NULL && vlan_tx_tag_present(skb))
                base_flags |= (TXD_FLAG_VLAN |
@@ -5329,7 +5313,6 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
        return 0;
 }
 
-#if TG3_TSO_SUPPORT != 0
 
 #define TG3_TSO_FW_RELEASE_MAJOR       0x1
 #define TG3_TSO_FW_RELASE_MINOR                0x6
@@ -5906,7 +5889,6 @@ static int tg3_load_tso_firmware(struct tg3 *tp)
        return 0;
 }
 
-#endif /* TG3_TSO_SUPPORT != 0 */
 
 /* tp->lock is held. */
 static void __tg3_set_mac_addr(struct tg3 *tp)
@@ -6120,7 +6102,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE);
                tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE);
        }
-#if TG3_TSO_SUPPORT != 0
        else if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
                int fw_len;
 
@@ -6135,7 +6116,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                tw32(BUFMGR_MB_POOL_SIZE,
                     NIC_SRAM_MBUF_POOL_SIZE5705 - fw_len - 0xa00);
        }
-#endif
 
        if (tp->dev->mtu <= ETH_DATA_LEN) {
                tw32(BUFMGR_MB_RDMA_LOW_WATER,
@@ -6337,10 +6317,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)
                rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST;
 
-#if TG3_TSO_SUPPORT != 0
        if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
                rdmac_mode |= (1 << 27);
-#endif
 
        /* Receive/send statistics. */
        if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) {
@@ -6511,10 +6489,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        tw32(RCVBDI_MODE, RCVBDI_MODE_ENABLE | RCVBDI_MODE_RCB_ATTN_ENAB);
        tw32(RCVDBDI_MODE, RCVDBDI_MODE_ENABLE | RCVDBDI_MODE_INV_RING_SZ);
        tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE);
-#if TG3_TSO_SUPPORT != 0
        if (tp->tg3_flags2 & TG3_FLG2_HW_TSO)
                tw32(SNDDATAI_MODE, SNDDATAI_MODE_ENABLE | 0x8);
-#endif
        tw32(SNDBDI_MODE, SNDBDI_MODE_ENABLE | SNDBDI_MODE_ATTN_ENABLE);
        tw32(SNDBDS_MODE, SNDBDS_MODE_ENABLE | SNDBDS_MODE_ATTN_ENABLE);
 
@@ -6524,13 +6500,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                        return err;
        }
 
-#if TG3_TSO_SUPPORT != 0
        if (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) {
                err = tg3_load_tso_firmware(tp);
                if (err)
                        return err;
        }
-#endif
 
        tp->tx_mode = TX_MODE_ENABLE;
        tw32_f(MAC_TX_MODE, tp->tx_mode);
@@ -8062,7 +8036,6 @@ static void tg3_set_msglevel(struct net_device *dev, u32 value)
        tp->msg_enable = value;
 }
 
-#if TG3_TSO_SUPPORT != 0
 static int tg3_set_tso(struct net_device *dev, u32 value)
 {
        struct tg3 *tp = netdev_priv(dev);
@@ -8081,7 +8054,6 @@ static int tg3_set_tso(struct net_device *dev, u32 value)
        }
        return ethtool_op_set_tso(dev, value);
 }
-#endif
 
 static int tg3_nway_reset(struct net_device *dev)
 {
@@ -9212,10 +9184,8 @@ static const struct ethtool_ops tg3_ethtool_ops = {
        .set_tx_csum            = tg3_set_tx_csum,
        .get_sg                 = ethtool_op_get_sg,
        .set_sg                 = ethtool_op_set_sg,
-#if TG3_TSO_SUPPORT != 0
        .get_tso                = ethtool_op_get_tso,
        .set_tso                = tg3_set_tso,
-#endif
        .self_test_count        = tg3_get_test_count,
        .self_test              = tg3_self_test,
        .get_strings            = tg3_get_strings,
@@ -11856,7 +11826,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
 
        tg3_init_bufmgr_config(tp);
 
-#if TG3_TSO_SUPPORT != 0
        if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) {
                tp->tg3_flags2 |= TG3_FLG2_TSO_CAPABLE;
        }
@@ -11881,7 +11850,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                        dev->features |= NETIF_F_TSO6;
        }
 
-#endif
 
        if (tp->pci_chip_rev_id == CHIPREV_ID_5705_A1 &&
            !(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) &&
index 7e4b23c..abb8611 100644 (file)
@@ -2865,8 +2865,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
                        if (UCC_GETH_TX_BD_RING_ALIGNMENT > 4)
                                align = UCC_GETH_TX_BD_RING_ALIGNMENT;
                        ugeth->tx_bd_ring_offset[j] =
-                               (u32) (kmalloc((u32) (length + align),
-                               GFP_KERNEL));
+                               kmalloc((u32) (length + align), GFP_KERNEL);
+
                        if (ugeth->tx_bd_ring_offset[j] != 0)
                                ugeth->p_tx_bd_ring[j] =
                                        (void*)((ugeth->tx_bd_ring_offset[j] +
@@ -2901,7 +2901,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
                        if (UCC_GETH_RX_BD_RING_ALIGNMENT > 4)
                                align = UCC_GETH_RX_BD_RING_ALIGNMENT;
                        ugeth->rx_bd_ring_offset[j] =
-                           (u32) (kmalloc((u32) (length + align), GFP_KERNEL));
+                               kmalloc((u32) (length + align), GFP_KERNEL);
                        if (ugeth->rx_bd_ring_offset[j] != 0)
                                ugeth->p_rx_bd_ring[j] =
                                        (void*)((ugeth->rx_bd_ring_offset[j] +
@@ -2927,10 +2927,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
        /* Init Tx bds */
        for (j = 0; j < ug_info->numQueuesTx; j++) {
                /* Setup the skbuff rings */
-               ugeth->tx_skbuff[j] =
-                   (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) *
-                                              ugeth->ug_info->bdRingLenTx[j],
-                                              GFP_KERNEL);
+               ugeth->tx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
+                                             ugeth->ug_info->bdRingLenTx[j],
+                                             GFP_KERNEL);
 
                if (ugeth->tx_skbuff[j] == NULL) {
                        ugeth_err("%s: Could not allocate tx_skbuff",
@@ -2959,10 +2958,9 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
        /* Init Rx bds */
        for (j = 0; j < ug_info->numQueuesRx; j++) {
                /* Setup the skbuff rings */
-               ugeth->rx_skbuff[j] =
-                   (struct sk_buff **)kmalloc(sizeof(struct sk_buff *) *
-                                              ugeth->ug_info->bdRingLenRx[j],
-                                              GFP_KERNEL);
+               ugeth->rx_skbuff[j] = kmalloc(sizeof(struct sk_buff *) *
+                                             ugeth->ug_info->bdRingLenRx[j],
+                                             GFP_KERNEL);
 
                if (ugeth->rx_skbuff[j] == NULL) {
                        ugeth_err("%s: Could not allocate rx_skbuff",
@@ -3453,8 +3451,7 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth)
         * allocated resources can be released when the channel is freed.
         */
        if (!(ugeth->p_init_enet_param_shadow =
-            (struct ucc_geth_init_pram *) kmalloc(sizeof(struct ucc_geth_init_pram),
-                                             GFP_KERNEL))) {
+             kmalloc(sizeof(struct ucc_geth_init_pram), GFP_KERNEL))) {
                ugeth_err
                    ("%s: Can not allocate memory for"
                        " p_UccInitEnetParamShadows.", __FUNCTION__);
index 21f76f5..61708cf 100644 (file)
@@ -235,6 +235,19 @@ comment "Cyclades-PC300 MLPPP support is disabled."
 comment "Refer to the file README.mlppp, provided by PC300 package."
        depends on WAN && HDLC && PC300 && (PPP=n || !PPP_MULTILINK || PPP_SYNC_TTY=n || !HDLC_PPP)
 
+config PC300TOO
+       tristate "Cyclades PC300 RSV/X21 alternative support"
+       depends on HDLC && PCI
+       help
+         Alternative driver for PC300 RSV/X21 PCI cards made by
+         Cyclades, Inc. If you have such a card, say Y here and see
+         <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
+
+         To compile this as a module, choose M here: the module
+         will be called pc300too.
+
+         If unsure, say N here.
+
 config N2
        tristate "SDL RISCom/N2 support"
        depends on HDLC && ISA
@@ -344,17 +357,6 @@ config DLCI
          To compile this driver as a module, choose M here: the
          module will be called dlci.
 
-config DLCI_COUNT
-       int "Max open DLCI"
-       depends on DLCI
-       default "24"
-       help
-         Maximal number of logical point-to-point frame relay connections
-         (the identifiers of which are called DCLIs) that the driver can
-         handle.
-
-         The default is probably fine.
-
 config DLCI_MAX
        int "Max DLCI per device"
        depends on DLCI
index 83ec2c8..d61fef3 100644 (file)
@@ -41,6 +41,7 @@ obj-$(CONFIG_N2)              += n2.o
 obj-$(CONFIG_C101)             += c101.o
 obj-$(CONFIG_WANXL)            += wanxl.o
 obj-$(CONFIG_PCI200SYN)                += pci200syn.o
+obj-$(CONFIG_PC300TOO)         += pc300too.o
 
 clean-files := wanxlfw.inc
 $(obj)/wanxl.o:        $(obj)/wanxlfw.inc
index db354e0..9040d7c 100644 (file)
@@ -222,7 +222,7 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        return -EINVAL;
 }
 
-void hdlc_setup(struct net_device *dev)
+static void hdlc_setup(struct net_device *dev)
 {
        hdlc_device *hdlc = dev_to_hdlc(dev);
 
@@ -325,7 +325,6 @@ MODULE_LICENSE("GPL v2");
 EXPORT_SYMBOL(hdlc_open);
 EXPORT_SYMBOL(hdlc_close);
 EXPORT_SYMBOL(hdlc_ioctl);
-EXPORT_SYMBOL(hdlc_setup);
 EXPORT_SYMBOL(alloc_hdlcdev);
 EXPORT_SYMBOL(unregister_hdlc_device);
 EXPORT_SYMBOL(register_hdlc_protocol);
diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c
new file mode 100644 (file)
index 0000000..79b2d54
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ * Cyclades PC300 synchronous serial card driver for Linux
+ *
+ * Copyright (C) 2000-2007 Krzysztof Halasa <khc@pm.waw.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License
+ * as published by the Free Software Foundation.
+ *
+ * For information see <http://www.kernel.org/pub/linux/utils/net/hdlc/>.
+ *
+ * Sources of information:
+ *    Hitachi HD64572 SCA-II User's Manual
+ *    Cyclades PC300 Linux driver
+ *
+ * This driver currently supports only PC300/RSV (V.24/V.35) and
+ * PC300/X21 cards.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/moduleparam.h>
+#include <linux/netdevice.h>
+#include <linux/hdlc.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include "hd64572.h"
+
+static const char* version = "Cyclades PC300 driver version: 1.17";
+static const char* devname = "PC300";
+
+#undef DEBUG_PKT
+#define DEBUG_RINGS
+
+#define PC300_PLX_SIZE         0x80    /* PLX control window size (128 B) */
+#define PC300_SCA_SIZE         0x400   /* SCA window size (1 KB) */
+#define ALL_PAGES_ALWAYS_MAPPED
+#define NEED_DETECT_RAM
+#define NEED_SCA_MSCI_INTR
+#define MAX_TX_BUFFERS         10
+
+static int pci_clock_freq = 33000000;
+static int use_crystal_clock = 0;
+static unsigned int CLOCK_BASE;
+
+/* Masks to access the init_ctrl PLX register */
+#define PC300_CLKSEL_MASK       (0x00000004UL)
+#define PC300_CHMEDIA_MASK(port) (0x00000020UL << ((port) * 3))
+#define PC300_CTYPE_MASK        (0x00000800UL)
+
+
+enum { PC300_RSV = 1, PC300_X21, PC300_TE }; /* card types */
+
+/*
+ *      PLX PCI9050-1 local configuration and shared runtime registers.
+ *      This structure can be used to access 9050 registers (memory mapped).
+ */
+typedef struct {
+       u32 loc_addr_range[4];  /* 00-0Ch : Local Address Ranges */
+       u32 loc_rom_range;      /* 10h : Local ROM Range */
+       u32 loc_addr_base[4];   /* 14-20h : Local Address Base Addrs */
+       u32 loc_rom_base;       /* 24h : Local ROM Base */
+       u32 loc_bus_descr[4];   /* 28-34h : Local Bus Descriptors */
+       u32 rom_bus_descr;      /* 38h : ROM Bus Descriptor */
+       u32 cs_base[4];         /* 3C-48h : Chip Select Base Addrs */
+       u32 intr_ctrl_stat;     /* 4Ch : Interrupt Control/Status */
+       u32 init_ctrl;          /* 50h : EEPROM ctrl, Init Ctrl, etc */
+}plx9050;
+
+
+
+typedef struct port_s {
+       struct net_device *dev;
+       struct card_s *card;
+       spinlock_t lock;        /* TX lock */
+       sync_serial_settings settings;
+       int rxpart;             /* partial frame received, next frame invalid*/
+       unsigned short encoding;
+       unsigned short parity;
+       unsigned int iface;
+       u16 rxin;               /* rx ring buffer 'in' pointer */
+       u16 txin;               /* tx ring buffer 'in' and 'last' pointers */
+       u16 txlast;
+       u8 rxs, txs, tmc;       /* SCA registers */
+       u8 phy_node;            /* physical port # - 0 or 1 */
+}port_t;
+
+
+
+typedef struct card_s {
+       int type;               /* RSV, X21, etc. */
+       int n_ports;            /* 1 or 2 ports */
+       u8* __iomem rambase;    /* buffer memory base (virtual) */
+       u8* __iomem scabase;    /* SCA memory base (virtual) */
+       plx9050 __iomem *plxbase; /* PLX registers memory base (virtual) */
+       u32 init_ctrl_value;    /* Saved value - 9050 bug workaround */
+       u16 rx_ring_buffers;    /* number of buffers in a ring */
+       u16 tx_ring_buffers;
+       u16 buff_offset;        /* offset of first buffer of first channel */
+       u8 irq;                 /* interrupt request level */
+
+       port_t ports[2];
+}card_t;
+
+
+#define sca_in(reg, card)           readb(card->scabase + (reg))
+#define sca_out(value, reg, card)    writeb(value, card->scabase + (reg))
+#define sca_inw(reg, card)          readw(card->scabase + (reg))
+#define sca_outw(value, reg, card)   writew(value, card->scabase + (reg))
+#define sca_inl(reg, card)          readl(card->scabase + (reg))
+#define sca_outl(value, reg, card)   writel(value, card->scabase + (reg))
+
+#define port_to_card(port)          (port->card)
+#define log_node(port)              (port->phy_node)
+#define phy_node(port)              (port->phy_node)
+#define winbase(card)               (card->rambase)
+#define get_port(card, port)        ((port) < (card)->n_ports ? \
+                                        (&(card)->ports[port]) : (NULL))
+
+#include "hd6457x.c"
+
+
+static void pc300_set_iface(port_t *port)
+{
+       card_t *card = port->card;
+       u32* init_ctrl = &card->plxbase->init_ctrl;
+       u16 msci = get_msci(port);
+       u8 rxs = port->rxs & CLK_BRG_MASK;
+       u8 txs = port->txs & CLK_BRG_MASK;
+
+       sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS,
+               port_to_card(port));
+       switch(port->settings.clock_type) {
+       case CLOCK_INT:
+               rxs |= CLK_BRG; /* BRG output */
+               txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
+               break;
+
+       case CLOCK_TXINT:
+               rxs |= CLK_LINE; /* RXC input */
+               txs |= CLK_PIN_OUT | CLK_BRG; /* BRG output */
+               break;
+
+       case CLOCK_TXFROMRX:
+               rxs |= CLK_LINE; /* RXC input */
+               txs |= CLK_PIN_OUT | CLK_TX_RXCLK; /* RX clock */
+               break;
+
+       default:                /* EXTernal clock */
+               rxs |= CLK_LINE; /* RXC input */
+               txs |= CLK_PIN_OUT | CLK_LINE; /* TXC input */
+               break;
+       }
+
+       port->rxs = rxs;
+       port->txs = txs;
+       sca_out(rxs, msci + RXS, card);
+       sca_out(txs, msci + TXS, card);
+       sca_set_port(port);
+
+       if (port->card->type == PC300_RSV) {
+               if (port->iface == IF_IFACE_V35)
+                       writel(card->init_ctrl_value |
+                              PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
+               else
+                       writel(card->init_ctrl_value &
+                              ~PC300_CHMEDIA_MASK(port->phy_node), init_ctrl);
+       }
+}
+
+
+
+static int pc300_open(struct net_device *dev)
+{
+       port_t *port = dev_to_port(dev);
+
+       int result = hdlc_open(dev);
+       if (result)
+               return result;
+
+       sca_open(dev);
+       pc300_set_iface(port);
+       return 0;
+}
+
+
+
+static int pc300_close(struct net_device *dev)
+{
+       sca_close(dev);
+       hdlc_close(dev);
+       return 0;
+}
+
+
+
+static int pc300_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+       const size_t size = sizeof(sync_serial_settings);
+       sync_serial_settings new_line;
+       sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync;
+       int new_type;
+       port_t *port = dev_to_port(dev);
+
+#ifdef DEBUG_RINGS
+       if (cmd == SIOCDEVPRIVATE) {
+               sca_dump_rings(dev);
+               return 0;
+       }
+#endif
+       if (cmd != SIOCWANDEV)
+               return hdlc_ioctl(dev, ifr, cmd);
+
+       if (ifr->ifr_settings.type == IF_GET_IFACE) {
+               ifr->ifr_settings.type = port->iface;
+               if (ifr->ifr_settings.size < size) {
+                       ifr->ifr_settings.size = size; /* data size wanted */
+                       return -ENOBUFS;
+               }
+               if (copy_to_user(line, &port->settings, size))
+                       return -EFAULT;
+               return 0;
+
+       }
+
+       if (port->card->type == PC300_X21 &&
+           (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL ||
+            ifr->ifr_settings.type == IF_IFACE_X21))
+               new_type = IF_IFACE_X21;
+
+       else if (port->card->type == PC300_RSV &&
+                (ifr->ifr_settings.type == IF_IFACE_SYNC_SERIAL ||
+                 ifr->ifr_settings.type == IF_IFACE_V35))
+               new_type = IF_IFACE_V35;
+
+       else if (port->card->type == PC300_RSV &&
+                ifr->ifr_settings.type == IF_IFACE_V24)
+               new_type = IF_IFACE_V24;
+
+       else
+               return hdlc_ioctl(dev, ifr, cmd);
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (copy_from_user(&new_line, line, size))
+               return -EFAULT;
+
+       if (new_line.clock_type != CLOCK_EXT &&
+           new_line.clock_type != CLOCK_TXFROMRX &&
+           new_line.clock_type != CLOCK_INT &&
+           new_line.clock_type != CLOCK_TXINT)
+               return -EINVAL; /* No such clock setting */
+
+       if (new_line.loopback != 0 && new_line.loopback != 1)
+               return -EINVAL;
+
+       memcpy(&port->settings, &new_line, size); /* Update settings */
+       port->iface = new_type;
+       pc300_set_iface(port);
+       return 0;
+}
+
+
+
+static void pc300_pci_remove_one(struct pci_dev *pdev)
+{
+       int i;
+       card_t *card = pci_get_drvdata(pdev);
+
+       for (i = 0; i < 2; i++)
+               if (card->ports[i].card) {
+                       struct net_device *dev = port_to_dev(&card->ports[i]);
+                       unregister_hdlc_device(dev);
+               }
+
+       if (card->irq)
+               free_irq(card->irq, card);
+
+       if (card->rambase)
+               iounmap(card->rambase);
+       if (card->scabase)
+               iounmap(card->scabase);
+       if (card->plxbase)
+               iounmap(card->plxbase);
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       pci_set_drvdata(pdev, NULL);
+       if (card->ports[0].dev)
+               free_netdev(card->ports[0].dev);
+       if (card->ports[1].dev)
+               free_netdev(card->ports[1].dev);
+       kfree(card);
+}
+
+
+
+static int __devinit pc300_pci_init_one(struct pci_dev *pdev,
+                                       const struct pci_device_id *ent)
+{
+       card_t *card;
+       u8 rev_id;
+       u32 __iomem *p;
+       int i;
+       u32 ramsize;
+       u32 ramphys;            /* buffer memory base */
+       u32 scaphys;            /* SCA memory base */
+       u32 plxphys;            /* PLX registers memory base */
+
+#ifndef MODULE
+       static int printed_version;
+       if (!printed_version++)
+               printk(KERN_INFO "%s\n", version);
+#endif
+
+       i = pci_enable_device(pdev);
+       if (i)
+               return i;
+
+       i = pci_request_regions(pdev, "PC300");
+       if (i) {
+               pci_disable_device(pdev);
+               return i;
+       }
+
+       card = kmalloc(sizeof(card_t), GFP_KERNEL);
+       if (card == NULL) {
+               printk(KERN_ERR "pc300: unable to allocate memory\n");
+               pci_release_regions(pdev);
+               pci_disable_device(pdev);
+               return -ENOBUFS;
+       }
+       memset(card, 0, sizeof(card_t));
+       pci_set_drvdata(pdev, card);
+
+       if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 ||
+           pdev->device == PCI_DEVICE_ID_PC300_TE_2)
+               card->type = PC300_TE; /* not fully supported */
+       else if (card->init_ctrl_value & PC300_CTYPE_MASK)
+               card->type = PC300_X21;
+       else
+               card->type = PC300_RSV;
+
+       if (pdev->device == PCI_DEVICE_ID_PC300_RX_1 ||
+           pdev->device == PCI_DEVICE_ID_PC300_TE_1)
+               card->n_ports = 1;
+       else
+               card->n_ports = 2;
+
+       for (i = 0; i < card->n_ports; i++)
+               if (!(card->ports[i].dev = alloc_hdlcdev(&card->ports[i]))) {
+                       printk(KERN_ERR "pc300: unable to allocate memory\n");
+                       pc300_pci_remove_one(pdev);
+                       return -ENOMEM;
+               }
+
+       pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+       if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE ||
+           pci_resource_len(pdev, 2) != PC300_SCA_SIZE ||
+           pci_resource_len(pdev, 3) < 16384) {
+               printk(KERN_ERR "pc300: invalid card EEPROM parameters\n");
+               pc300_pci_remove_one(pdev);
+               return -EFAULT;
+       }
+
+       plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK;
+       card->plxbase = ioremap(plxphys, PC300_PLX_SIZE);
+
+       scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK;
+       card->scabase = ioremap(scaphys, PC300_SCA_SIZE);
+
+       ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK;
+       card->rambase = ioremap(ramphys, pci_resource_len(pdev,3));
+
+       if (card->plxbase == NULL ||
+           card->scabase == NULL ||
+           card->rambase == NULL) {
+               printk(KERN_ERR "pc300: ioremap() failed\n");
+               pc300_pci_remove_one(pdev);
+       }
+
+       /* PLX PCI 9050 workaround for local configuration register read bug */
+       pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, scaphys);
+       card->init_ctrl_value = readl(&((plx9050*)card->scabase)->init_ctrl);
+       pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys);
+
+       /* Reset PLX */
+       p = &card->plxbase->init_ctrl;
+       writel(card->init_ctrl_value | 0x40000000, p);
+       readl(p);               /* Flush the write - do not use sca_flush */
+       udelay(1);
+
+       writel(card->init_ctrl_value, p);
+       readl(p);               /* Flush the write - do not use sca_flush */
+       udelay(1);
+
+       /* Reload Config. Registers from EEPROM */
+       writel(card->init_ctrl_value | 0x20000000, p);
+       readl(p);               /* Flush the write - do not use sca_flush */
+       udelay(1);
+
+       writel(card->init_ctrl_value, p);
+       readl(p);               /* Flush the write - do not use sca_flush */
+       udelay(1);
+
+       ramsize = sca_detect_ram(card, card->rambase,
+                                pci_resource_len(pdev, 3));
+
+       if (use_crystal_clock)
+               card->init_ctrl_value &= ~PC300_CLKSEL_MASK;
+       else
+               card->init_ctrl_value |= PC300_CLKSEL_MASK;
+
+       writel(card->init_ctrl_value, &card->plxbase->init_ctrl);
+       /* number of TX + RX buffers for one port */
+       i = ramsize / (card->n_ports * (sizeof(pkt_desc) + HDLC_MAX_MRU));
+       card->tx_ring_buffers = min(i / 2, MAX_TX_BUFFERS);
+       card->rx_ring_buffers = i - card->tx_ring_buffers;
+
+       card->buff_offset = card->n_ports * sizeof(pkt_desc) *
+               (card->tx_ring_buffers + card->rx_ring_buffers);
+
+       printk(KERN_INFO "pc300: PC300/%s, %u KB RAM at 0x%x, IRQ%u, "
+              "using %u TX + %u RX packets rings\n",
+              card->type == PC300_X21 ? "X21" :
+              card->type == PC300_TE ? "TE" : "RSV",
+              ramsize / 1024, ramphys, pdev->irq,
+              card->tx_ring_buffers, card->rx_ring_buffers);
+
+       if (card->tx_ring_buffers < 1) {
+               printk(KERN_ERR "pc300: RAM test failed\n");
+               pc300_pci_remove_one(pdev);
+               return -EFAULT;
+       }
+
+       /* Enable interrupts on the PCI bridge, LINTi1 active low */
+       writew(0x0041, &card->plxbase->intr_ctrl_stat);
+
+       /* Allocate IRQ */
+       if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) {
+               printk(KERN_WARNING "pc300: could not allocate IRQ%d.\n",
+                      pdev->irq);
+               pc300_pci_remove_one(pdev);
+               return -EBUSY;
+       }
+       card->irq = pdev->irq;
+
+       sca_init(card, 0);
+
+       // COTE not set - allows better TX DMA settings
+       // sca_out(sca_in(PCR, card) | PCR_COTE, PCR, card);
+
+       sca_out(0x10, BTCR, card);
+
+       for (i = 0; i < card->n_ports; i++) {
+               port_t *port = &card->ports[i];
+               struct net_device *dev = port_to_dev(port);
+               hdlc_device *hdlc = dev_to_hdlc(dev);
+               port->phy_node = i;
+
+               spin_lock_init(&port->lock);
+               SET_MODULE_OWNER(dev);
+               dev->irq = card->irq;
+               dev->mem_start = ramphys;
+               dev->mem_end = ramphys + ramsize - 1;
+               dev->tx_queue_len = 50;
+               dev->do_ioctl = pc300_ioctl;
+               dev->open = pc300_open;
+               dev->stop = pc300_close;
+               hdlc->attach = sca_attach;
+               hdlc->xmit = sca_xmit;
+               port->settings.clock_type = CLOCK_EXT;
+               port->card = card;
+               if (card->type == PC300_X21)
+                       port->iface = IF_IFACE_X21;
+               else
+                       port->iface = IF_IFACE_V35;
+
+               if (register_hdlc_device(dev)) {
+                       printk(KERN_ERR "pc300: unable to register hdlc "
+                              "device\n");
+                       port->card = NULL;
+                       pc300_pci_remove_one(pdev);
+                       return -ENOBUFS;
+               }
+               sca_init_sync_port(port);       /* Set up SCA memory */
+
+               printk(KERN_INFO "%s: PC300 node %d\n",
+                      dev->name, port->phy_node);
+       }
+       return 0;
+}
+
+
+
+static struct pci_device_id pc300_pci_tbl[] __devinitdata = {
+       { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_1, PCI_ANY_ID,
+         PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_RX_2, PCI_ANY_ID,
+         PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_1, PCI_ANY_ID,
+         PCI_ANY_ID, 0, 0, 0 },
+       { PCI_VENDOR_ID_CYCLADES, PCI_DEVICE_ID_PC300_TE_2, PCI_ANY_ID,
+         PCI_ANY_ID, 0, 0, 0 },
+       { 0, }
+};
+
+
+static struct pci_driver pc300_pci_driver = {
+       name:           "PC300",
+       id_table:       pc300_pci_tbl,
+       probe:          pc300_pci_init_one,
+       remove:         pc300_pci_remove_one,
+};
+
+
+static int __init pc300_init_module(void)
+{
+#ifdef MODULE
+       printk(KERN_INFO "%s\n", version);
+#endif
+       if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) {
+               printk(KERN_ERR "pc300: Invalid PCI clock frequency\n");
+               return -EINVAL;
+       }
+       if (use_crystal_clock != 0 && use_crystal_clock != 1) {
+               printk(KERN_ERR "pc300: Invalid 'use_crystal_clock' value\n");
+               return -EINVAL;
+       }
+
+       CLOCK_BASE = use_crystal_clock ? 24576000 : pci_clock_freq;
+
+       return pci_module_init(&pc300_pci_driver);
+}
+
+
+
+static void __exit pc300_cleanup_module(void)
+{
+       pci_unregister_driver(&pc300_pci_driver);
+}
+
+MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
+MODULE_DESCRIPTION("Cyclades PC300 serial port driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(pci, pc300_pci_tbl);
+module_param(pci_clock_freq, int, 0444);
+MODULE_PARM_DESC(pci_clock_freq, "System PCI clock frequency in Hz");
+module_param(use_crystal_clock, int, 0444);
+MODULE_PARM_DESC(use_crystal_clock,
+                "Use 24.576 MHz clock instead of PCI clock");
+module_init(pc300_init_module);
+module_exit(pc300_cleanup_module);
index 59ddd21..8dbcf83 100644 (file)
@@ -331,8 +331,7 @@ static void z8530_rtsdtr(struct z8530_channel *c, int set)
 static void z8530_rx(struct z8530_channel *c)
 {
        u8 ch,stat;
-       spin_lock(c->lock);
+
        while(1)
        {
                /* FIFO empty ? */
@@ -390,7 +389,6 @@ static void z8530_rx(struct z8530_channel *c)
         */
        write_zsctrl(c, ERR_RES);
        write_zsctrl(c, RES_H_IUS);
-       spin_unlock(c->lock);
 }
 
 
@@ -406,7 +404,6 @@ static void z8530_rx(struct z8530_channel *c)
  
 static void z8530_tx(struct z8530_channel *c)
 {
-       spin_lock(c->lock);
        while(c->txcount) {
                /* FIFO full ? */
                if(!(read_zsreg(c, R0)&4))
@@ -434,7 +431,6 @@ static void z8530_tx(struct z8530_channel *c)
 
        z8530_tx_done(c);        
        write_zsctrl(c, RES_H_IUS);
-       spin_unlock(c->lock);
 }
 
 /**
@@ -452,7 +448,6 @@ static void z8530_status(struct z8530_channel *chan)
 {
        u8 status, altered;
 
-       spin_lock(chan->lock);
        status=read_zsreg(chan, R0);
        altered=chan->status^status;
        
@@ -487,7 +482,6 @@ static void z8530_status(struct z8530_channel *chan)
        }       
        write_zsctrl(chan, RES_EXT_INT);
        write_zsctrl(chan, RES_H_IUS);
-       spin_unlock(chan->lock);
 }
 
 struct z8530_irqhandler z8530_sync=
@@ -511,7 +505,6 @@ EXPORT_SYMBOL(z8530_sync);
  
 static void z8530_dma_rx(struct z8530_channel *chan)
 {
-       spin_lock(chan->lock);
        if(chan->rxdma_on)
        {
                /* Special condition check only */
@@ -534,7 +527,6 @@ static void z8530_dma_rx(struct z8530_channel *chan)
                /* DMA is off right now, drain the slow way */
                z8530_rx(chan);
        }       
-       spin_unlock(chan->lock);
 }
 
 /**
@@ -547,7 +539,6 @@ static void z8530_dma_rx(struct z8530_channel *chan)
  
 static void z8530_dma_tx(struct z8530_channel *chan)
 {
-       spin_lock(chan->lock);
        if(!chan->dma_tx)
        {
                printk(KERN_WARNING "Hey who turned the DMA off?\n");
@@ -557,7 +548,6 @@ static void z8530_dma_tx(struct z8530_channel *chan)
        /* This shouldnt occur in DMA mode */
        printk(KERN_ERR "DMA tx - bogus event!\n");
        z8530_tx(chan);
-       spin_unlock(chan->lock);
 }
 
 /**
@@ -596,7 +586,6 @@ static void z8530_dma_status(struct z8530_channel *chan)
                }
        }
 
-       spin_lock(chan->lock);
        if(altered&chan->dcdcheck)
        {
                if(status&chan->dcdcheck)
@@ -618,7 +607,6 @@ static void z8530_dma_status(struct z8530_channel *chan)
 
        write_zsctrl(chan, RES_EXT_INT);
        write_zsctrl(chan, RES_H_IUS);
-       spin_unlock(chan->lock);
 }
 
 struct z8530_irqhandler z8530_dma_sync=
index 8286678..3a064de 100644 (file)
 #define BCM43xx_UCODEFLAG_UNKPACTRL    0x0040
 #define BCM43xx_UCODEFLAG_JAPAN                0x0080
 
+/* Hardware Radio Enable masks */
+#define BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK (1 << 16)
+#define BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK (1 << 4)
+
 /* Generic-Interrupt reasons. */
 #define BCM43xx_IRQ_READY              (1 << 0)
 #define BCM43xx_IRQ_BEACON             (1 << 1)
@@ -758,7 +762,8 @@ struct bcm43xx_private {
            bad_frames_preempt:1,       /* Use "Bad Frames Preemption" (default off) */
            reg124_set_0x4:1,           /* Some variable to keep track of IRQ stuff. */
            short_preamble:1,           /* TRUE, if short preamble is enabled. */
-           firmware_norelease:1;       /* Do not release the firmware. Used on suspend. */
+           firmware_norelease:1,       /* Do not release the firmware. Used on suspend. */
+           radio_hw_enable:1;          /* TRUE if radio is hardware enabled */
 
        struct bcm43xx_stats stats;
 
index 7d383a2..8f198be 100644 (file)
@@ -26,6 +26,7 @@
 */
 
 #include "bcm43xx_leds.h"
+#include "bcm43xx_radio.h"
 #include "bcm43xx.h"
 
 #include <asm/bitops.h>
@@ -108,6 +109,7 @@ static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm,
        switch (led_index) {
        case 0:
                led->behaviour = BCM43xx_LED_ACTIVITY;
+               led->activelow = 1;
                if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
                        led->behaviour = BCM43xx_LED_RADIO_ALL;
                break;
@@ -199,20 +201,21 @@ void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
                        turn_on = activity;
                        break;
                case BCM43xx_LED_RADIO_ALL:
-                       turn_on = radio->enabled;
+                       turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm);
                        break;
                case BCM43xx_LED_RADIO_A:
                case BCM43xx_LED_BCM4303_2:
-                       turn_on = (radio->enabled && phy->type == BCM43xx_PHYTYPE_A);
+                       turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
+                                  phy->type == BCM43xx_PHYTYPE_A);
                        break;
                case BCM43xx_LED_RADIO_B:
                case BCM43xx_LED_BCM4303_1:
-                       turn_on = (radio->enabled &&
+                       turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
                                   (phy->type == BCM43xx_PHYTYPE_B ||
                                    phy->type == BCM43xx_PHYTYPE_G));
                        break;
                case BCM43xx_LED_MODE_BG:
-                       if (phy->type == BCM43xx_PHYTYPE_G &&
+                       if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) &&
                            1/*FIXME: using G rates.*/)
                                turn_on = 1;
                        break;
index 91b752e..23aaf1e 100644 (file)
@@ -2441,6 +2441,9 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
        if (err)
                goto err_gpio_cleanup;
        bcm43xx_radio_turn_on(bcm);
+       bcm->radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+       dprintk(KERN_INFO PFX "Radio %s by hardware\n",
+               (bcm->radio_hw_enable == 0) ? "disabled" : "enabled");
 
        bcm43xx_write16(bcm, 0x03E6, 0x0000);
        err = bcm43xx_phy_init(bcm);
@@ -3174,10 +3177,25 @@ static void bcm43xx_periodic_every30sec(struct bcm43xx_private *bcm)
 }
 
 static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
+{
+       bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
+       //TODO for APHY (temperature?)
+}
+
+static void bcm43xx_periodic_every1sec(struct bcm43xx_private *bcm)
 {
        struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
        struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
+       int radio_hw_enable;
 
+       /* check if radio hardware enabled status changed */
+       radio_hw_enable = bcm43xx_is_hw_radio_enabled(bcm);
+       if (unlikely(bcm->radio_hw_enable != radio_hw_enable)) {
+               bcm->radio_hw_enable = radio_hw_enable;
+               dprintk(KERN_INFO PFX "Radio hardware status changed to %s\n",
+                      (radio_hw_enable == 0) ? "disabled" : "enabled");
+               bcm43xx_leds_update(bcm, 0);
+       }
        if (phy->type == BCM43xx_PHYTYPE_G) {
                //TODO: update_aci_moving_average
                if (radio->aci_enable && radio->aci_wlan_automatic) {
@@ -3201,21 +3219,21 @@ static void bcm43xx_periodic_every15sec(struct bcm43xx_private *bcm)
                        //TODO: implement rev1 workaround
                }
        }
-       bcm43xx_phy_xmitpower(bcm); //FIXME: unless scanning?
-       //TODO for APHY (temperature?)
 }
 
 static void do_periodic_work(struct bcm43xx_private *bcm)
 {
-       if (bcm->periodic_state % 8 == 0)
+       if (bcm->periodic_state % 120 == 0)
                bcm43xx_periodic_every120sec(bcm);
-       if (bcm->periodic_state % 4 == 0)
+       if (bcm->periodic_state % 60 == 0)
                bcm43xx_periodic_every60sec(bcm);
-       if (bcm->periodic_state % 2 == 0)
+       if (bcm->periodic_state % 30 == 0)
                bcm43xx_periodic_every30sec(bcm);
-       bcm43xx_periodic_every15sec(bcm);
+       if (bcm->periodic_state % 15 == 0)
+               bcm43xx_periodic_every15sec(bcm);
+       bcm43xx_periodic_every1sec(bcm);
 
-       schedule_delayed_work(&bcm->periodic_work, HZ * 15);
+       schedule_delayed_work(&bcm->periodic_work, HZ);
 }
 
 static void bcm43xx_periodic_work_handler(struct work_struct *work)
@@ -3228,7 +3246,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
        unsigned long orig_trans_start = 0;
 
        mutex_lock(&bcm->mutex);
-       if (unlikely(bcm->periodic_state % 4 == 0)) {
+       if (unlikely(bcm->periodic_state % 60 == 0)) {
                /* Periodic work will take a long time, so we want it to
                 * be preemtible.
                 */
@@ -3260,7 +3278,7 @@ static void bcm43xx_periodic_work_handler(struct work_struct *work)
 
        do_periodic_work(bcm);
 
-       if (unlikely(bcm->periodic_state % 4 == 0)) {
+       if (unlikely(bcm->periodic_state % 60 == 0)) {
                spin_lock_irqsave(&bcm->irq_lock, flags);
                tasklet_enable(&bcm->isr_tasklet);
                bcm43xx_interrupt_enable(bcm, savedirqs);
index bb9c484..af19a07 100644 (file)
@@ -1981,6 +1981,7 @@ void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm)
        }
        radio->enabled = 1;
        dprintk(KERN_INFO PFX "Radio turned on\n");
+       bcm43xx_leds_update(bcm, 0);
 }
        
 void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
@@ -2001,6 +2002,7 @@ void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm)
                bcm43xx_phy_write(bcm, 0x0015, 0xAA00);
        radio->enabled = 0;
        dprintk(KERN_INFO PFX "Radio turned off\n");
+       bcm43xx_leds_update(bcm, 0);
 }
 
 void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm)
index 9ed1803..77a98a5 100644 (file)
@@ -65,6 +65,22 @@ void bcm43xx_radio_init2060(struct bcm43xx_private *bcm);
 void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm);
 void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm);
 
+static inline
+int bcm43xx_is_hw_radio_enabled(struct bcm43xx_private *bcm)
+{
+       /* function to return state of hardware enable of radio
+        * returns 0 if radio disabled, 1 if radio enabled
+        */
+       if (bcm->current_core->rev >= 3)
+               return ((bcm43xx_read32(bcm, BCM43xx_MMIO_RADIO_HWENABLED_HI)
+                                       & BCM43xx_MMIO_RADIO_HWENABLED_HI_MASK)
+                                       == 0) ? 1 : 0;
+       else
+               return ((bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_HWENABLED_LO)
+                                       & BCM43xx_MMIO_RADIO_HWENABLED_LO_MASK)
+                                       == 0) ? 0 : 1;
+}
+
 int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel,
                                int synthetic_pu_workaround);
 
index 04c19ce..9077e6e 100644 (file)
@@ -84,7 +84,7 @@ struct net_device * hostap_add_interface(struct local_info *local,
        if (strchr(dev->name, '%'))
                ret = dev_alloc_name(dev, dev->name);
 
-       SET_NETDEV_DEV(dev, mdev->class_dev.dev);
+       SET_NETDEV_DEV(dev, mdev->dev.parent);
        if (ret >= 0)
                ret = register_netdevice(dev);
 
index 22cb3fb..c878a2f 100644 (file)
@@ -9166,7 +9166,7 @@ static int ipw_wx_set_rts(struct net_device *dev,
 {
        struct ipw_priv *priv = ieee80211_priv(dev);
        mutex_lock(&priv->mutex);
-       if (wrqu->rts.disabled)
+       if (wrqu->rts.disabled || !wrqu->rts.fixed)
                priv->rts_threshold = DEFAULT_RTS_THRESHOLD;
        else {
                if (wrqu->rts.value < MIN_RTS_THRESHOLD ||
@@ -9255,7 +9255,7 @@ static int ipw_wx_set_frag(struct net_device *dev,
 {
        struct ipw_priv *priv = ieee80211_priv(dev);
        mutex_lock(&priv->mutex);
-       if (wrqu->frag.disabled)
+       if (wrqu->frag.disabled || !wrqu->frag.fixed)
                priv->ieee->fts = DEFAULT_FTS;
        else {
                if (wrqu->frag.value < MIN_FRAG_THRESHOLD ||
index 936c888..4e7f6cf 100644 (file)
@@ -2059,7 +2059,7 @@ static int determine_firmware(struct net_device *dev)
        int err;
        struct comp_id nic_id, sta_id;
        unsigned int firmver;
-       char tmp[SYMBOL_MAX_VER_LEN+1];
+       char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
 
        /* Get the hardware version */
        err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
@@ -4293,8 +4293,8 @@ static void orinoco_get_drvinfo(struct net_device *dev,
        strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
        strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
        strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
-       if (dev->class_dev.dev)
-               strncpy(info->bus_info, dev->class_dev.dev->bus_id,
+       if (dev->dev.parent)
+               strncpy(info->bus_info, dev->dev.parent->bus_id,
                        sizeof(info->bus_info) - 1);
        else
                snprintf(info->bus_info, sizeof(info->bus_info) - 1,
index d08ae8d..d1e5022 100644 (file)
@@ -332,7 +332,7 @@ orinoco_cs_config(struct pcmcia_device *link)
 
        /* Finally, report what we've done */
        printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
-              "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+              "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
               link->irq.AssignedIRQ, link->io.BasePort1,
               link->io.BasePort1 + link->io.NumPorts1 - 1);
 
index f057fd9..a037b11 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/module.h>
 
 #include <linux/netdevice.h>
+#include <linux/ethtool.h>
 #include <linux/pci.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
@@ -787,6 +788,17 @@ islpci_set_multicast_list(struct net_device *dev)
 }
 #endif
 
+static void islpci_ethtool_get_drvinfo(struct net_device *dev,
+                                       struct ethtool_drvinfo *info)
+{
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+}
+
+static struct ethtool_ops islpci_ethtool_ops = {
+       .get_drvinfo = islpci_ethtool_get_drvinfo,
+};
+
 struct net_device *
 islpci_setup(struct pci_dev *pdev)
 {
@@ -813,6 +825,7 @@ islpci_setup(struct pci_dev *pdev)
        ndev->do_ioctl = &prism54_ioctl;
        ndev->wireless_handlers =
            (struct iw_handler_def *) &prism54_handler_def;
+       ndev->ethtool_ops = &islpci_ethtool_ops;
 
        ndev->hard_start_xmit = &islpci_eth_transmit;
        /* ndev->set_multicast_list = &islpci_set_multicast_list; */
index a9aa166..736666d 100644 (file)
@@ -211,4 +211,8 @@ islpci_trigger(islpci_private *priv)
 
 int islpci_free_memory(islpci_private *);
 struct net_device *islpci_setup(struct pci_dev *);
+
+#define DRV_NAME       "prism54"
+#define DRV_VERSION    "1.2"
+
 #endif                         /* _ISLPCI_DEV_H */
index 58257b4..3dcb13b 100644 (file)
@@ -28,9 +28,6 @@
 #include "islpci_mgt.h"                /* for pc_debug */
 #include "isl_oid.h"
 
-#define DRV_NAME       "prism54"
-#define DRV_VERSION    "1.2"
-
 MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>");
 MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter");
 MODULE_LICENSE("GPL");
index cf2d148..af70460 100644 (file)
@@ -806,7 +806,7 @@ spectrum_cs_config(struct pcmcia_device *link)
 
        /* Finally, report what we've done */
        printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io "
-              "0x%04x-0x%04x\n", dev->name, dev->class_dev.dev->bus_id,
+              "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id,
               link->irq.AssignedIRQ, link->io.BasePort1,
               link->io.BasePort1 + link->io.NumPorts1 - 1);
 
index 78ea72f..12dfc0b 100644 (file)
@@ -84,6 +84,18 @@ static void print_id(struct zd_chip *chip)
        dev_info(zd_chip_dev(chip), "%s\n", buffer);
 }
 
+static zd_addr_t inc_addr(zd_addr_t addr)
+{
+       u16 a = (u16)addr;
+       /* Control registers use byte addressing, but everything else uses word
+        * addressing. */
+       if ((a & 0xf000) == CR_START)
+               a += 2;
+       else
+               a += 1;
+       return (zd_addr_t)a;
+}
+
 /* Read a variable number of 32-bit values. Parameter count is not allowed to
  * exceed USB_MAX_IOREAD32_COUNT.
  */
@@ -114,7 +126,7 @@ int zd_ioread32v_locked(struct zd_chip *chip, u32 *values, const zd_addr_t *addr
        for (i = 0; i < count; i++) {
                int j = 2*i;
                /* We read the high word always first. */
-               a16[j] = zd_inc_word(addr[i]);
+               a16[j] = inc_addr(addr[i]);
                a16[j+1] = addr[i];
        }
 
@@ -163,7 +175,7 @@ int _zd_iowrite32v_locked(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
                j = 2*i;
                /* We write the high word always first. */
                ioreqs16[j].value   = ioreqs[i].value >> 16;
-               ioreqs16[j].addr    = zd_inc_word(ioreqs[i].addr);
+               ioreqs16[j].addr    = inc_addr(ioreqs[i].addr);
                ioreqs16[j+1].value = ioreqs[i].value;
                ioreqs16[j+1].addr  = ioreqs[i].addr;
        }
@@ -466,7 +478,8 @@ static int read_values(struct zd_chip *chip, u8 *values, size_t count,
 
        ZD_ASSERT(mutex_is_locked(&chip->mutex));
        for (i = 0;;) {
-               r = zd_ioread32_locked(chip, &v, e2p_addr+i/2);
+               r = zd_ioread32_locked(chip, &v,
+                                      (zd_addr_t)((u16)e2p_addr+i/2));
                if (r)
                        return r;
                v -= guard;
@@ -798,47 +811,18 @@ static int hw_reset_phy(struct zd_chip *chip)
 static int zd1211_hw_init_hmac(struct zd_chip *chip)
 {
        static const struct zd_ioreq32 ioreqs[] = {
-               { CR_ACK_TIMEOUT_EXT,           0x20 },
-               { CR_ADDA_MBIAS_WARMTIME,       0x30000808 },
                { CR_ZD1211_RETRY_MAX,          0x2 },
-               { CR_SNIFFER_ON,                0 },
-               { CR_RX_FILTER,                 STA_RX_FILTER },
-               { CR_GROUP_HASH_P1,             0x00 },
-               { CR_GROUP_HASH_P2,             0x80000000 },
-               { CR_REG1,                      0xa4 },
-               { CR_ADDA_PWR_DWN,              0x7f },
-               { CR_BCN_PLCP_CFG,              0x00f00401 },
-               { CR_PHY_DELAY,                 0x00 },
-               { CR_ACK_TIMEOUT_EXT,           0x80 },
-               { CR_ADDA_PWR_DWN,              0x00 },
-               { CR_ACK_TIME_80211,            0x100 },
-               { CR_RX_PE_DELAY,               0x70 },
-               { CR_PS_CTRL,                   0x10000000 },
-               { CR_RTS_CTS_RATE,              0x02030203 },
                { CR_RX_THRESHOLD,              0x000c0640 },
-               { CR_AFTER_PNP,                 0x1 },
-               { CR_WEP_PROTECT,               0x114 },
        };
 
-       int r;
-
        dev_dbg_f(zd_chip_dev(chip), "\n");
        ZD_ASSERT(mutex_is_locked(&chip->mutex));
-       r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
-#ifdef DEBUG
-       if (r) {
-               dev_err(zd_chip_dev(chip),
-                       "error in zd_iowrite32a_locked. Error number %d\n", r);
-       }
-#endif /* DEBUG */
-       return r;
+       return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
 
 static int zd1211b_hw_init_hmac(struct zd_chip *chip)
 {
        static const struct zd_ioreq32 ioreqs[] = {
-               { CR_ACK_TIMEOUT_EXT,           0x20 },
-               { CR_ADDA_MBIAS_WARMTIME,       0x30000808 },
                { CR_ZD1211B_RETRY_MAX,         0x02020202 },
                { CR_ZD1211B_TX_PWR_CTL4,       0x007f003f },
                { CR_ZD1211B_TX_PWR_CTL3,       0x007f003f },
@@ -847,6 +831,20 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
                { CR_ZD1211B_AIFS_CTL1,         0x00280028 },
                { CR_ZD1211B_AIFS_CTL2,         0x008C003C },
                { CR_ZD1211B_TXOP,              0x01800824 },
+               { CR_RX_THRESHOLD,              0x000c0eff, },
+       };
+
+       dev_dbg_f(zd_chip_dev(chip), "\n");
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
+}
+
+static int hw_init_hmac(struct zd_chip *chip)
+{
+       int r;
+       static const struct zd_ioreq32 ioreqs[] = {
+               { CR_ACK_TIMEOUT_EXT,           0x20 },
+               { CR_ADDA_MBIAS_WARMTIME,       0x30000808 },
                { CR_SNIFFER_ON,                0 },
                { CR_RX_FILTER,                 STA_RX_FILTER },
                { CR_GROUP_HASH_P1,             0x00 },
@@ -861,25 +859,16 @@ static int zd1211b_hw_init_hmac(struct zd_chip *chip)
                { CR_RX_PE_DELAY,               0x70 },
                { CR_PS_CTRL,                   0x10000000 },
                { CR_RTS_CTS_RATE,              0x02030203 },
-               { CR_RX_THRESHOLD,              0x000c0eff, },
                { CR_AFTER_PNP,                 0x1 },
                { CR_WEP_PROTECT,               0x114 },
+               { CR_IFS_VALUE,                 IFS_VALUE_DEFAULT },
        };
 
-       int r;
-
-       dev_dbg_f(zd_chip_dev(chip), "\n");
        ZD_ASSERT(mutex_is_locked(&chip->mutex));
        r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
-       if (r) {
-               dev_dbg_f(zd_chip_dev(chip),
-                       "error in zd_iowrite32a_locked. Error number %d\n", r);
-       }
-       return r;
-}
+       if (r)
+               return r;
 
-static int hw_init_hmac(struct zd_chip *chip)
-{
        return chip->is_zd1211b ?
                zd1211b_hw_init_hmac(chip) : zd1211_hw_init_hmac(chip);
 }
@@ -974,16 +963,14 @@ static int hw_init(struct zd_chip *chip)
        if (r)
                return r;
 
-       /* Although the vendor driver defaults to a different value during
-        * init, it overwrites the IFS value with the following every time
-        * the channel changes. We should aim to be more intelligent... */
-       r = zd_iowrite32_locked(chip, IFS_VALUE_DEFAULT, CR_IFS_VALUE);
-       if (r)
-               return r;
-
        return set_beacon_interval(chip, 100);
 }
 
+static zd_addr_t fw_reg_addr(struct zd_chip *chip, u16 offset)
+{
+       return (zd_addr_t)((u16)chip->fw_regs_base + offset);
+}
+
 #ifdef DEBUG
 static int dump_cr(struct zd_chip *chip, const zd_addr_t addr,
                   const char *addr_string)
@@ -1018,9 +1005,11 @@ static int test_init(struct zd_chip *chip)
 
 static void dump_fw_registers(struct zd_chip *chip)
 {
-       static const zd_addr_t addr[4] = {
-               FW_FIRMWARE_VER, FW_USB_SPEED, FW_FIX_TX_RATE,
-               FW_LINK_STATUS
+       const zd_addr_t addr[4] = {
+               fw_reg_addr(chip, FW_REG_FIRMWARE_VER),
+               fw_reg_addr(chip, FW_REG_USB_SPEED),
+               fw_reg_addr(chip, FW_REG_FIX_TX_RATE),
+               fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
        };
 
        int r;
@@ -1046,7 +1035,8 @@ static int print_fw_version(struct zd_chip *chip)
        int r;
        u16 version;
 
-       r = zd_ioread16_locked(chip, &version, FW_FIRMWARE_VER);
+       r = zd_ioread16_locked(chip, &version,
+               fw_reg_addr(chip, FW_REG_FIRMWARE_VER));
        if (r)
                return r;
 
@@ -1126,6 +1116,22 @@ int zd_chip_disable_hwint(struct zd_chip *chip)
        return r;
 }
 
+static int read_fw_regs_offset(struct zd_chip *chip)
+{
+       int r;
+
+       ZD_ASSERT(mutex_is_locked(&chip->mutex));
+       r = zd_ioread16_locked(chip, (u16*)&chip->fw_regs_base,
+                              FWRAW_REGS_ADDR);
+       if (r)
+               return r;
+       dev_dbg_f(zd_chip_dev(chip), "fw_regs_base: %#06hx\n",
+                 (u16)chip->fw_regs_base);
+
+       return 0;
+}
+
+
 int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
 {
        int r;
@@ -1145,7 +1151,7 @@ int zd_chip_init_hw(struct zd_chip *chip, u8 device_type)
        if (r)
                goto out;
 
-       r = zd_usb_init_hw(&chip->usb);
+       r = read_fw_regs_offset(chip);
        if (r)
                goto out;
 
@@ -1325,15 +1331,15 @@ u8 zd_chip_get_channel(struct zd_chip *chip)
 
 int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
 {
-       static const zd_addr_t a[] = {
-               FW_LINK_STATUS,
+       const zd_addr_t a[] = {
+               fw_reg_addr(chip, FW_REG_LED_LINK_STATUS),
                CR_LED,
        };
 
        int r;
        u16 v[ARRAY_SIZE(a)];
        struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = {
-               [0] = { FW_LINK_STATUS },
+               [0] = { fw_reg_addr(chip, FW_REG_LED_LINK_STATUS) },
                [1] = { CR_LED },
        };
        u16 other_led;
index a4e3cee..b07569e 100644 (file)
@@ -18,7 +18,6 @@
 #ifndef _ZD_CHIP_H
 #define _ZD_CHIP_H
 
-#include "zd_types.h"
 #include "zd_rf.h"
 #include "zd_usb.h"
 
  * adds a processor for handling the USB protocol.
  */
 
+/* Address space */
+enum {
+       /* CONTROL REGISTERS */
+       CR_START                        = 0x9000,
+
+
+       /* FIRMWARE */
+       FW_START                        = 0xee00,
+
+
+       /* EEPROM */
+       E2P_START                       = 0xf800,
+       E2P_LEN                         = 0x800,
+
+       /* EEPROM layout */
+       E2P_LOAD_CODE_LEN               = 0xe,          /* base 0xf800 */
+       E2P_LOAD_VECT_LEN               = 0x9,          /* base 0xf80e */
+       /* E2P_DATA indexes into this */
+       E2P_DATA_LEN                    = 0x7e,         /* base 0xf817 */
+       E2P_BOOT_CODE_LEN               = 0x760,        /* base 0xf895 */
+       E2P_INTR_VECT_LEN               = 0xb,          /* base 0xfff5 */
+
+       /* Some precomputed offsets into the EEPROM */
+       E2P_DATA_OFFSET                 = E2P_LOAD_CODE_LEN + E2P_LOAD_VECT_LEN,
+       E2P_BOOT_CODE_OFFSET            = E2P_DATA_OFFSET + E2P_DATA_LEN,
+};
+
+#define CTL_REG(offset) ((zd_addr_t)(CR_START + (offset)))
+#define E2P_DATA(offset) ((zd_addr_t)(E2P_START + E2P_DATA_OFFSET + (offset)))
+#define FWRAW_DATA(offset) ((zd_addr_t)(FW_START + (offset)))
+
 /* 8-bit hardware registers */
 #define CR0   CTL_REG(0x0000)
 #define CR1   CTL_REG(0x0004)
 
 #define CR_MAX_PHY_REG 255
 
-/* Taken from the ZYDAS driver, not all of them are relevant for the ZSD1211
+/* Taken from the ZYDAS driver, not all of them are relevant for the ZD1211
  * driver.
  */
 
 /*
  * Upper 16 bit contains the regulatory domain.
  */
-#define E2P_SUBID              E2P_REG(0x00)
-#define E2P_POD                        E2P_REG(0x02)
-#define E2P_MAC_ADDR_P1                E2P_REG(0x04)
-#define E2P_MAC_ADDR_P2                E2P_REG(0x06)
-#define E2P_PWR_CAL_VALUE1     E2P_REG(0x08)
-#define E2P_PWR_CAL_VALUE2     E2P_REG(0x0a)
-#define E2P_PWR_CAL_VALUE3     E2P_REG(0x0c)
-#define E2P_PWR_CAL_VALUE4      E2P_REG(0x0e)
-#define E2P_PWR_INT_VALUE1     E2P_REG(0x10)
-#define E2P_PWR_INT_VALUE2     E2P_REG(0x12)
-#define E2P_PWR_INT_VALUE3     E2P_REG(0x14)
-#define E2P_PWR_INT_VALUE4     E2P_REG(0x16)
+#define E2P_SUBID              E2P_DATA(0x00)
+#define E2P_POD                        E2P_DATA(0x02)
+#define E2P_MAC_ADDR_P1                E2P_DATA(0x04)
+#define E2P_MAC_ADDR_P2                E2P_DATA(0x06)
+#define E2P_PWR_CAL_VALUE1     E2P_DATA(0x08)
+#define E2P_PWR_CAL_VALUE2     E2P_DATA(0x0a)
+#define E2P_PWR_CAL_VALUE3     E2P_DATA(0x0c)
+#define E2P_PWR_CAL_VALUE4      E2P_DATA(0x0e)
+#define E2P_PWR_INT_VALUE1     E2P_DATA(0x10)
+#define E2P_PWR_INT_VALUE2     E2P_DATA(0x12)
+#define E2P_PWR_INT_VALUE3     E2P_DATA(0x14)
+#define E2P_PWR_INT_VALUE4     E2P_DATA(0x16)
 
 /* Contains a bit for each allowed channel. It gives for Europe (ETSI 0x30)
  * also only 11 channels. */
-#define E2P_ALLOWED_CHANNEL    E2P_REG(0x18)
-
-#define E2P_PHY_REG            E2P_REG(0x1a)
-#define E2P_DEVICE_VER         E2P_REG(0x20)
-#define E2P_36M_CAL_VALUE1     E2P_REG(0x28)
-#define E2P_36M_CAL_VALUE2      E2P_REG(0x2a)
-#define E2P_36M_CAL_VALUE3      E2P_REG(0x2c)
-#define E2P_36M_CAL_VALUE4     E2P_REG(0x2e)
-#define E2P_11A_INT_VALUE1     E2P_REG(0x30)
-#define E2P_11A_INT_VALUE2     E2P_REG(0x32)
-#define E2P_11A_INT_VALUE3     E2P_REG(0x34)
-#define E2P_11A_INT_VALUE4     E2P_REG(0x36)
-#define E2P_48M_CAL_VALUE1     E2P_REG(0x38)
-#define E2P_48M_CAL_VALUE2     E2P_REG(0x3a)
-#define E2P_48M_CAL_VALUE3     E2P_REG(0x3c)
-#define E2P_48M_CAL_VALUE4     E2P_REG(0x3e)
-#define E2P_48M_INT_VALUE1     E2P_REG(0x40)
-#define E2P_48M_INT_VALUE2     E2P_REG(0x42)
-#define E2P_48M_INT_VALUE3     E2P_REG(0x44)
-#define E2P_48M_INT_VALUE4     E2P_REG(0x46)
-#define E2P_54M_CAL_VALUE1     E2P_REG(0x48)   /* ??? */
-#define E2P_54M_CAL_VALUE2     E2P_REG(0x4a)
-#define E2P_54M_CAL_VALUE3     E2P_REG(0x4c)
-#define E2P_54M_CAL_VALUE4     E2P_REG(0x4e)
-#define E2P_54M_INT_VALUE1     E2P_REG(0x50)
-#define E2P_54M_INT_VALUE2     E2P_REG(0x52)
-#define E2P_54M_INT_VALUE3     E2P_REG(0x54)
-#define E2P_54M_INT_VALUE4     E2P_REG(0x56)
-
-/* All 16 bit values */
-#define FW_FIRMWARE_VER         FW_REG(0)
-/* non-zero if USB high speed connection */
-#define FW_USB_SPEED            FW_REG(1)
-#define FW_FIX_TX_RATE          FW_REG(2)
-/* Seems to be able to control LEDs over the firmware */
-#define FW_LINK_STATUS          FW_REG(3)
-#define FW_SOFT_RESET           FW_REG(4)
-#define FW_FLASH_CHK            FW_REG(5)
+#define E2P_ALLOWED_CHANNEL    E2P_DATA(0x18)
+
+#define E2P_PHY_REG            E2P_DATA(0x1a)
+#define E2P_DEVICE_VER         E2P_DATA(0x20)
+#define E2P_36M_CAL_VALUE1     E2P_DATA(0x28)
+#define E2P_36M_CAL_VALUE2      E2P_DATA(0x2a)
+#define E2P_36M_CAL_VALUE3      E2P_DATA(0x2c)
+#define E2P_36M_CAL_VALUE4     E2P_DATA(0x2e)
+#define E2P_11A_INT_VALUE1     E2P_DATA(0x30)
+#define E2P_11A_INT_VALUE2     E2P_DATA(0x32)
+#define E2P_11A_INT_VALUE3     E2P_DATA(0x34)
+#define E2P_11A_INT_VALUE4     E2P_DATA(0x36)
+#define E2P_48M_CAL_VALUE1     E2P_DATA(0x38)
+#define E2P_48M_CAL_VALUE2     E2P_DATA(0x3a)
+#define E2P_48M_CAL_VALUE3     E2P_DATA(0x3c)
+#define E2P_48M_CAL_VALUE4     E2P_DATA(0x3e)
+#define E2P_48M_INT_VALUE1     E2P_DATA(0x40)
+#define E2P_48M_INT_VALUE2     E2P_DATA(0x42)
+#define E2P_48M_INT_VALUE3     E2P_DATA(0x44)
+#define E2P_48M_INT_VALUE4     E2P_DATA(0x46)
+#define E2P_54M_CAL_VALUE1     E2P_DATA(0x48)  /* ??? */
+#define E2P_54M_CAL_VALUE2     E2P_DATA(0x4a)
+#define E2P_54M_CAL_VALUE3     E2P_DATA(0x4c)
+#define E2P_54M_CAL_VALUE4     E2P_DATA(0x4e)
+#define E2P_54M_INT_VALUE1     E2P_DATA(0x50)
+#define E2P_54M_INT_VALUE2     E2P_DATA(0x52)
+#define E2P_54M_INT_VALUE3     E2P_DATA(0x54)
+#define E2P_54M_INT_VALUE4     E2P_DATA(0x56)
+
+/* This word contains the base address of the FW_REG_ registers below */
+#define FWRAW_REGS_ADDR                FWRAW_DATA(0x1d)
+
+/* All 16 bit values, offset from the address in FWRAW_REGS_ADDR */
+enum {
+       FW_REG_FIRMWARE_VER     = 0,
+       /* non-zero if USB high speed connection */
+       FW_REG_USB_SPEED        = 1,
+       FW_REG_FIX_TX_RATE      = 2,
+       /* Seems to be able to control LEDs over the firmware */
+       FW_REG_LED_LINK_STATUS  = 3,
+       FW_REG_SOFT_RESET       = 4,
+       FW_REG_FLASH_CHK        = 5,
+};
 
+/* Values for FW_LINK_STATUS */
 #define FW_LINK_OFF            0x0
 #define FW_LINK_TX             0x1
 /* 0x2 - link led on? */
 
-enum {
-       CR_BASE_OFFSET                  = 0x9000,
-       FW_START_OFFSET                 = 0xee00,
-       FW_BASE_ADDR_OFFSET             = FW_START_OFFSET + 0x1d,
-       EEPROM_START_OFFSET             = 0xf800,
-       EEPROM_SIZE                     = 0x800, /* words */
-       LOAD_CODE_SIZE                  = 0xe, /* words */
-       LOAD_VECT_SIZE                  = 0x10000 - 0xfff7, /* words */
-       EEPROM_REGS_OFFSET              = LOAD_CODE_SIZE + LOAD_VECT_SIZE,
-       EEPROM_REGS_SIZE                = 0x7e, /* words */
-       E2P_BASE_OFFSET                 = EEPROM_START_OFFSET +
-                                         EEPROM_REGS_OFFSET,
-};
-
-#define FW_REG_TABLE_ADDR      USB_ADDR(FW_START_OFFSET + 0x1d)
-
 enum {
        /* indices for ofdm_cal_values */
        OFDM_36M_INDEX = 0,
@@ -679,6 +699,8 @@ struct zd_chip {
        struct zd_usb usb;
        struct zd_rf rf;
        struct mutex mutex;
+       /* Base address of FW_REG_ registers */
+       zd_addr_t fw_regs_base;
        u8 e2p_mac[ETH_ALEN];
        /* EepSetPoint in the vendor driver */
        u8 pwr_cal_values[E2P_CHANNEL_COUNT];
index fb22f62..deb99d1 100644 (file)
@@ -23,6 +23,8 @@
 #include <linux/device.h>
 #include <linux/kernel.h>
 
+typedef u16 __nocast zd_addr_t;
+
 #define dev_printk_f(level, dev, fmt, args...) \
        dev_printk(level, dev, "%s() " fmt, __func__, ##args)
 
index 26b8298..c4f36d3 100644 (file)
@@ -2,7 +2,6 @@
 #define _ZD_IEEE80211_H
 
 #include <net/ieee80211.h>
-#include "zd_types.h"
 
 /* Additional definitions from the standards.
  */
index 676b373..a57732e 100644 (file)
@@ -18,8 +18,6 @@
 #ifndef _ZD_RF_H
 #define _ZD_RF_H
 
-#include "zd_types.h"
-
 #define UW2451_RF                      0x2
 #define UCHIP_RF                       0x3
 #define AL2230_RF                      0x4
diff --git a/drivers/net/wireless/zd1211rw/zd_types.h b/drivers/net/wireless/zd1211rw/zd_types.h
deleted file mode 100644 (file)
index 0155a15..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/* zd_types.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 _ZD_TYPES_H
-#define _ZD_TYPES_H
-
-#include <linux/types.h>
-
-/* We have three register spaces mapped into the overall USB address space of
- * 64K words (16-bit values). There is the control register space of
- * double-word registers, the eeprom register space and the firmware register
- * space. The control register space is byte mapped, the others are word
- * mapped.
- *
- * For that reason, we are using byte offsets for control registers and word
- * offsets for everything else.
- */
-
-typedef u32 __nocast zd_addr_t;
-
-enum {
-       ADDR_BASE_MASK          = 0xff000000,
-       ADDR_OFFSET_MASK        = 0x0000ffff,
-       ADDR_ZERO_MASK          = 0x00ff0000,
-       NULL_BASE               = 0x00000000,
-       USB_BASE                = 0x01000000,
-       CR_BASE                 = 0x02000000,
-       CR_MAX_OFFSET           = 0x0b30,
-       E2P_BASE                = 0x03000000,
-       E2P_MAX_OFFSET          = 0x007e,
-       FW_BASE                 = 0x04000000,
-       FW_MAX_OFFSET           = 0x0005,
-};
-
-#define ZD_ADDR_BASE(addr) ((u32)(addr) & ADDR_BASE_MASK)
-#define ZD_OFFSET(addr) ((u32)(addr) & ADDR_OFFSET_MASK)
-
-#define ZD_ADDR(base, offset) \
-       ((zd_addr_t)(((base) & ADDR_BASE_MASK) | ((offset) & ADDR_OFFSET_MASK)))
-
-#define ZD_NULL_ADDR    ((zd_addr_t)0)
-#define USB_REG(offset)  ZD_ADDR(USB_BASE, offset)     /* word addressing */
-#define CTL_REG(offset)  ZD_ADDR(CR_BASE, offset)      /* byte addressing */
-#define E2P_REG(offset)  ZD_ADDR(E2P_BASE, offset)     /* word addressing */
-#define FW_REG(offset)   ZD_ADDR(FW_BASE, offset)      /* word addressing */
-
-static inline zd_addr_t zd_inc_word(zd_addr_t addr)
-{
-       u32 base = ZD_ADDR_BASE(addr);
-       u32 offset = ZD_OFFSET(addr);
-
-       offset += base == CR_BASE ? 2 : 1;
-
-       return base | offset;
-}
-
-#endif /* _ZD_TYPES_H */
index 605e96e..75ef556 100644 (file)
@@ -58,6 +58,10 @@ static struct usb_device_id usb_ids[] = {
        { USB_DEVICE(0x079b, 0x0062), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x1582, 0x6003), .driver_info = DEVICE_ZD1211B },
        { USB_DEVICE(0x050d, 0x705c), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x083a, 0x4505), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0471, 0x1236), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x13b1, 0x0024), .driver_info = DEVICE_ZD1211B },
+       { USB_DEVICE(0x0586, 0x340f), .driver_info = DEVICE_ZD1211B },
        /* "Driverless" devices that need ejecting */
        { USB_DEVICE(0x0ace, 0x2011), .driver_info = DEVICE_INSTALLER },
        {}
@@ -73,96 +77,6 @@ MODULE_DEVICE_TABLE(usb, usb_ids);
 #define FW_ZD1211_PREFIX       "zd1211/zd1211_"
 #define FW_ZD1211B_PREFIX      "zd1211/zd1211b_"
 
-/* register address handling */
-
-#ifdef DEBUG
-static int check_addr(struct zd_usb *usb, zd_addr_t addr)
-{
-       u32 base = ZD_ADDR_BASE(addr);
-       u32 offset = ZD_OFFSET(addr);
-
-       if ((u32)addr & ADDR_ZERO_MASK)
-               goto invalid_address;
-       switch (base) {
-       case USB_BASE:
-               break;
-       case CR_BASE:
-               if (offset > CR_MAX_OFFSET) {
-                       dev_dbg(zd_usb_dev(usb),
-                               "CR offset %#010x larger than"
-                               " CR_MAX_OFFSET %#10x\n",
-                               offset, CR_MAX_OFFSET);
-                       goto invalid_address;
-               }
-               if (offset & 1) {
-                       dev_dbg(zd_usb_dev(usb),
-                               "CR offset %#010x is not a multiple of 2\n",
-                               offset);
-                       goto invalid_address;
-               }
-               break;
-       case E2P_BASE:
-               if (offset > E2P_MAX_OFFSET) {
-                       dev_dbg(zd_usb_dev(usb),
-                               "E2P offset %#010x larger than"
-                               " E2P_MAX_OFFSET %#010x\n",
-                               offset, E2P_MAX_OFFSET);
-                       goto invalid_address;
-               }
-               break;
-       case FW_BASE:
-               if (!usb->fw_base_offset) {
-                       dev_dbg(zd_usb_dev(usb),
-                              "ERROR: fw base offset has not been set\n");
-                       return -EAGAIN;
-               }
-               if (offset > FW_MAX_OFFSET) {
-                       dev_dbg(zd_usb_dev(usb),
-                               "FW offset %#10x is larger than"
-                               " FW_MAX_OFFSET %#010x\n",
-                               offset, FW_MAX_OFFSET);
-                       goto invalid_address;
-               }
-               break;
-       default:
-               dev_dbg(zd_usb_dev(usb),
-                       "address has unsupported base %#010x\n", addr);
-               goto invalid_address;
-       }
-
-       return 0;
-invalid_address:
-       dev_dbg(zd_usb_dev(usb),
-               "ERROR: invalid address: %#010x\n", addr);
-       return -EINVAL;
-}
-#endif /* DEBUG */
-
-static u16 usb_addr(struct zd_usb *usb, zd_addr_t addr)
-{
-       u32 base;
-       u16 offset;
-
-       base = ZD_ADDR_BASE(addr);
-       offset = ZD_OFFSET(addr);
-
-       ZD_ASSERT(check_addr(usb, addr) == 0);
-
-       switch (base) {
-       case CR_BASE:
-               offset += CR_BASE_OFFSET;
-               break;
-       case E2P_BASE:
-               offset += E2P_BASE_OFFSET;
-               break;
-       case FW_BASE:
-               offset += usb->fw_base_offset;
-               break;
-       }
-
-       return offset;
-}
-
 /* USB device initialization */
 
 static int request_fw_file(
@@ -295,14 +209,13 @@ static int handle_version_mismatch(struct usb_device *udev, u8 device_type,
        if (r)
                goto error;
 
-       r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START_OFFSET,
-               REBOOT);
+       r = upload_code(udev, ur_fw->data, ur_fw->size, FW_START, REBOOT);
        if (r)
                goto error;
 
-       offset = ((EEPROM_REGS_OFFSET + EEPROM_REGS_SIZE) * sizeof(u16));
+       offset = (E2P_BOOT_CODE_OFFSET * sizeof(u16));
        r = upload_code(udev, ub_fw->data + offset, ub_fw->size - offset,
-               E2P_BASE_OFFSET + EEPROM_REGS_SIZE, REBOOT);
+               E2P_START + E2P_BOOT_CODE_OFFSET, REBOOT);
 
        /* At this point, the vendor driver downloads the whole firmware
         * image, hacks around with version IDs, and uploads it again,
@@ -331,7 +244,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
        if (r)
                goto error;
 
-       fw_bcdDevice = get_word(ub_fw->data, EEPROM_REGS_OFFSET);
+       fw_bcdDevice = get_word(ub_fw->data, E2P_DATA_OFFSET);
 
        if (fw_bcdDevice != bcdDevice) {
                dev_info(&udev->dev,
@@ -357,8 +270,7 @@ static int upload_firmware(struct usb_device *udev, u8 device_type)
        if (r)
                goto error;
 
-       r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START_OFFSET,
-                       REBOOT);
+       r = upload_code(udev, uph_fw->data, uph_fw->size, FW_START, REBOOT);
        if (r) {
                dev_err(&udev->dev,
                        "Could not upload firmware code uph. Error number %d\n",
@@ -858,7 +770,7 @@ static inline void init_usb_interrupt(struct zd_usb *usb)
        spin_lock_init(&intr->lock);
        intr->interval = int_urb_interval(zd_usb_to_usbdev(usb));
        init_completion(&intr->read_regs.completion);
-       intr->read_regs.cr_int_addr = cpu_to_le16(usb_addr(usb, CR_INTERRUPT));
+       intr->read_regs.cr_int_addr = cpu_to_le16((u16)CR_INTERRUPT);
 }
 
 static inline void init_usb_rx(struct zd_usb *usb)
@@ -890,22 +802,6 @@ void zd_usb_init(struct zd_usb *usb, struct net_device *netdev,
        init_usb_rx(usb);
 }
 
-int zd_usb_init_hw(struct zd_usb *usb)
-{
-       int r;
-       struct zd_chip *chip = zd_usb_to_chip(usb);
-
-       ZD_ASSERT(mutex_is_locked(&chip->mutex));
-       r = zd_ioread16_locked(chip, &usb->fw_base_offset,
-                       USB_REG((u16)FW_BASE_ADDR_OFFSET));
-       if (r)
-               return r;
-       dev_dbg_f(zd_usb_dev(usb), "fw_base_offset: %#06hx\n",
-                usb->fw_base_offset);
-
-       return 0;
-}
-
 void zd_usb_clear(struct zd_usb *usb)
 {
        usb_set_intfdata(usb->intf, NULL);
@@ -1253,7 +1149,7 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
                return -ENOMEM;
        req->id = cpu_to_le16(USB_REQ_READ_REGS);
        for (i = 0; i < count; i++)
-               req->addr[i] = cpu_to_le16(usb_addr(usb, addresses[i]));
+               req->addr[i] = cpu_to_le16((u16)addresses[i]);
 
        udev = zd_usb_to_usbdev(usb);
        prepare_read_regs_int(usb);
@@ -1318,7 +1214,7 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
        req->id = cpu_to_le16(USB_REQ_WRITE_REGS);
        for (i = 0; i < count; i++) {
                struct reg_data *rw  = &req->reg_writes[i];
-               rw->addr = cpu_to_le16(usb_addr(usb, ioreqs[i].addr));
+               rw->addr = cpu_to_le16((u16)ioreqs[i].addr);
                rw->value = cpu_to_le16(ioreqs[i].value);
        }
 
index 317d37c..506ea6a 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/usb.h>
 
 #include "zd_def.h"
-#include "zd_types.h"
 
 enum devicetype {
        DEVICE_ZD1211  = 0,
@@ -181,15 +180,14 @@ struct zd_usb_tx {
        spinlock_t lock;
 };
 
-/* Contains the usb parts. The structure doesn't require a lock, because intf
- * and fw_base_offset, will not be changed after initialization.
+/* Contains the usb parts. The structure doesn't require a lock because intf
+ * will not be changed after initialization.
  */
 struct zd_usb {
        struct zd_usb_interrupt intr;
        struct zd_usb_rx rx;
        struct zd_usb_tx tx;
        struct usb_interface *intf;
-       u16 fw_base_offset;
 };
 
 #define zd_usb_dev(usb) (&usb->intf->dev)
index adce420..be92695 100644 (file)
@@ -145,15 +145,6 @@ config HOTPLUG_PCI_SHPC
 
          When in doubt, say N.
 
-config HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
-       bool "Use polling mechanism for hot-plug events (for testing purpose)"
-       depends on HOTPLUG_PCI_SHPC
-       help
-         Say Y here if you want to use the polling mechanism for hot-plug 
-         events for early platform testing.
-
-         When in doubt, say N.
-
 config HOTPLUG_PCI_RPA
        tristate "RPA PCI Hotplug driver"
        depends on HOTPLUG_PCI && PPC_PSERIES && PPC64 && !HOTPLUG_PCI_FAKE
index bd1faeb..fca978f 100644 (file)
@@ -773,13 +773,13 @@ static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
                goto out;
 
        table = obj->buffer.pointer;
-       switch (((acpi_table_entry_header *)table)->type) {
-       case ACPI_MADT_IOSAPIC:
-               *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base;
+       switch (((struct acpi_subtable_header *)table)->type) {
+       case ACPI_MADT_TYPE_IO_SAPIC:
+               *gsi_base = ((struct acpi_madt_io_sapic *)table)->global_irq_base;
                result = 0;
                break;
-       case ACPI_MADT_IOAPIC:
-               *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base;
+       case ACPI_MADT_TYPE_IO_APIC:
+               *gsi_base = ((struct acpi_madt_io_apic *)table)->global_irq_base;
                result = 0;
                break;
        default:
index 4fb12fc..d19fcae 100644 (file)
@@ -44,15 +44,20 @@ extern int pciehp_poll_time;
 extern int pciehp_debug;
 extern int pciehp_force;
 
-/*#define dbg(format, arg...) do { if (pciehp_debug) printk(KERN_DEBUG "%s: " format, MY_NAME , ## arg); } while (0)*/
-#define dbg(format, arg...) do { if (pciehp_debug) printk("%s: " format, MY_NAME , ## arg); } while (0)
-#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
-
+#define dbg(format, arg...)                                            \
+       do {                                                            \
+               if (pciehp_debug)                                       \
+                       printk("%s: " format, MY_NAME , ## arg);        \
+       } while (0)
+#define err(format, arg...)                                            \
+       printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...)                                           \
+       printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+#define warn(format, arg...)                                           \
+       printk(KERN_WARNING "%s: " format, MY_NAME , ## arg)
 
+#define SLOT_NAME_SIZE 10
 struct slot {
-       struct slot *next;
        u8 bus;
        u8 device;
        u32 number;
@@ -63,6 +68,8 @@ struct slot {
        struct hpc_ops *hpc_ops;
        struct hotplug_slot *hotplug_slot;
        struct list_head        slot_list;
+       char name[SLOT_NAME_SIZE];
+       unsigned long last_emi_toggle;
 };
 
 struct event_info {
@@ -70,34 +77,15 @@ struct event_info {
        u8 hp_slot;
 };
 
-typedef u8(*php_intr_callback_t) (u8 hp_slot, void *instance_id);
-
-struct php_ctlr_state_s {
-       struct php_ctlr_state_s *pnext;
-       struct pci_dev *pci_dev;
-       unsigned int irq;
-       unsigned long flags;                            /* spinlock's */
-       u32 slot_device_offset;
-       u32 num_slots;
-       struct timer_list       int_poll_timer;         /* Added for poll event */
-       php_intr_callback_t     attention_button_callback;
-       php_intr_callback_t     switch_change_callback;
-       php_intr_callback_t     presence_change_callback;
-       php_intr_callback_t     power_fault_callback;
-       void                    *callback_instance_id;
-       struct ctrl_reg         *creg;                          /* Ptr to controller register space */
-};
-
 #define MAX_EVENTS             10
 struct controller {
        struct controller *next;
        struct mutex crit_sect;         /* critical section mutex */
        struct mutex ctrl_lock;         /* controller lock */
-       struct php_ctlr_state_s *hpc_ctlr_handle; /* HPC controller handle */
        int num_slots;                  /* Number of slots on ctlr */
        int slot_num_inc;               /* 1 or -1 */
        struct pci_dev *pci_dev;
-       struct pci_bus *pci_bus;
+       struct list_head slot_list;
        struct event_info event_queue[MAX_EVENTS];
        struct slot *slot;
        struct hpc_ops *hpc_ops;
@@ -112,6 +100,8 @@ struct controller {
        u8 ctrlcap;
        u16 vendor_id;
        u8 cap_base;
+       struct timer_list poll_timer;
+       volatile int cmd_busy;
 };
 
 #define INT_BUTTON_IGNORE              0
@@ -131,8 +121,6 @@ struct controller {
 #define POWERON_STATE                  3
 #define POWEROFF_STATE                 4
 
-#define PCI_TO_PCI_BRIDGE_CLASS                0x00060400
-
 /* Error messages */
 #define INTERLOCK_OPEN                 0x00000002
 #define ADD_NOT_SUPPORTED              0x00000003
@@ -144,10 +132,6 @@ struct controller {
 #define WRONG_BUS_FREQUENCY            0x0000000D
 #define POWER_FAILURE                  0x0000000E
 
-#define REMOVE_NOT_SUPPORTED           0x00000003
-
-#define DISABLE_CARD                   1
-
 /* Field definitions in Slot Capabilities Register */
 #define ATTN_BUTTN_PRSN        0x00000001
 #define        PWR_CTRL_PRSN   0x00000002
@@ -155,6 +139,7 @@ struct controller {
 #define ATTN_LED_PRSN  0x00000008
 #define PWR_LED_PRSN   0x00000010
 #define HP_SUPR_RM_SUP 0x00000020
+#define EMI_PRSN       0x00020000
 
 #define ATTN_BUTTN(cap)                (cap & ATTN_BUTTN_PRSN)
 #define POWER_CTRL(cap)                (cap & PWR_CTRL_PRSN)
@@ -162,130 +147,65 @@ struct controller {
 #define ATTN_LED(cap)          (cap & ATTN_LED_PRSN)
 #define PWR_LED(cap)           (cap & PWR_LED_PRSN) 
 #define HP_SUPR_RM(cap)                (cap & HP_SUPR_RM_SUP)
-
-/*
- * error Messages
- */
-#define msg_initialization_err "Initialization failure, error=%d\n"
-#define msg_button_on          "PCI slot #%s - powering on due to button press.\n"
-#define msg_button_off         "PCI slot #%s - powering off due to button press.\n"
-#define msg_button_cancel      "PCI slot #%s - action canceled due to button press.\n"
-#define msg_button_ignore      "PCI slot #%s - button press ignored.  (action in progress...)\n"
-
-/* controller functions */
-extern int     pciehp_event_start_thread       (void);
-extern void    pciehp_event_stop_thread        (void);
-extern int     pciehp_enable_slot              (struct slot *slot);
-extern int     pciehp_disable_slot             (struct slot *slot);
-
-extern u8      pciehp_handle_attention_button  (u8 hp_slot, void *inst_id);
-extern u8      pciehp_handle_switch_change     (u8 hp_slot, void *inst_id);
-extern u8      pciehp_handle_presence_change   (u8 hp_slot, void *inst_id);
-extern u8      pciehp_handle_power_fault       (u8 hp_slot, void *inst_id);
-/* extern void long_delay (int delay); */
-
-/* pci functions */
-extern int     pciehp_configure_device         (struct slot *p_slot);
-extern int     pciehp_unconfigure_device       (struct slot *p_slot);
-
-
+#define EMI(cap)               (cap & EMI_PRSN)
+
+extern int pciehp_event_start_thread(void);
+extern void pciehp_event_stop_thread(void);
+extern int pciehp_enable_slot(struct slot *slot);
+extern int pciehp_disable_slot(struct slot *slot);
+extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
+extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
+extern int pciehp_configure_device(struct slot *p_slot);
+extern int pciehp_unconfigure_device(struct slot *p_slot);
+int pcie_init(struct controller *ctrl, struct pcie_device *dev);
 
 /* Global variables */
 extern struct controller *pciehp_ctrl_list;
 
-/* Inline functions */
-
 static inline struct slot *pciehp_find_slot(struct controller *ctrl, u8 device)
 {
-       struct slot *p_slot, *tmp_slot = NULL;
-
-       p_slot = ctrl->slot;
+       struct slot *slot;
 
-       while (p_slot && (p_slot->device != device)) {
-               tmp_slot = p_slot;
-               p_slot = p_slot->next;
+       list_for_each_entry(slot, &ctrl->slot_list, slot_list) {
+               if (slot->device == device)
+                       return slot;
        }
-       if (p_slot == NULL) {
-               err("ERROR: pciehp_find_slot device=0x%x\n", device);
-               p_slot = tmp_slot;
-       }
-
-       return p_slot;
-}
-
-static inline int wait_for_ctrl_irq(struct controller *ctrl)
-{
-       int retval = 0;
-
-       DECLARE_WAITQUEUE(wait, current);
-
-       add_wait_queue(&ctrl->queue, &wait);
-       if (!pciehp_poll_mode)
-               /* Sleep for up to 1 second */
-               msleep_interruptible(1000);
-       else
-               msleep_interruptible(2500);
-       
-       remove_wait_queue(&ctrl->queue, &wait);
-       if (signal_pending(current))
-               retval =  -EINTR;
-
-       return retval;
-}
-
-#define SLOT_NAME_SIZE 10
 
-static inline void make_slot_name(char *buffer, int buffer_size, struct slot *slot)
-{
-       snprintf(buffer, buffer_size, "%04d_%04d", slot->bus, slot->number);
+       err("%s: slot (device=0x%x) not found\n", __FUNCTION__, device);
+       return NULL;
 }
 
-enum php_ctlr_type {
-       PCI,
-       ISA,
-       ACPI
-};
-
-int pcie_init(struct controller *ctrl, struct pcie_device *dev);
-
-/* This has no meaning for PCI Express, as there is only 1 slot per port */
-int pcie_get_ctlr_slot_config(struct controller *ctrl,
-               int *num_ctlr_slots,
-               int *first_device_num,
-               int *physical_slot_num,
-               u8 *ctrlcap);
-
 struct hpc_ops {
-       int     (*power_on_slot)        (struct slot *slot);
-       int     (*power_off_slot)       (struct slot *slot);
-       int     (*get_power_status)     (struct slot *slot, u8 *status);
-       int     (*get_attention_status) (struct slot *slot, u8 *status);
-       int     (*set_attention_status) (struct slot *slot, u8 status);
-       int     (*get_latch_status)     (struct slot *slot, u8 *status);
-       int     (*get_adapter_status)   (struct slot *slot, u8 *status);
-
-       int     (*get_max_bus_speed)    (struct slot *slot, enum pci_bus_speed *speed);
-       int     (*get_cur_bus_speed)    (struct slot *slot, enum pci_bus_speed *speed);
-
-       int     (*get_max_lnk_width)    (struct slot *slot, enum pcie_link_width *value);
-       int     (*get_cur_lnk_width)    (struct slot *slot, enum pcie_link_width *value);
-       
-       int     (*query_power_fault)    (struct slot *slot);
-       void    (*green_led_on)         (struct slot *slot);
-       void    (*green_led_off)        (struct slot *slot);
-       void    (*green_led_blink)      (struct slot *slot);
-       void    (*release_ctlr)         (struct controller *ctrl);
-       int     (*check_lnk_status)     (struct controller *ctrl);
+       int (*power_on_slot)(struct slot *slot);
+       int (*power_off_slot)(struct slot *slot);
+       int (*get_power_status)(struct slot *slot, u8 *status);
+       int (*get_attention_status)(struct slot *slot, u8 *status);
+       int (*set_attention_status)(struct slot *slot, u8 status);
+       int (*get_latch_status)(struct slot *slot, u8 *status);
+       int (*get_adapter_status)(struct slot *slot, u8 *status);
+       int (*get_emi_status)(struct slot *slot, u8 *status);
+       int (*toggle_emi)(struct slot *slot);
+       int (*get_max_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+       int (*get_cur_bus_speed)(struct slot *slot, enum pci_bus_speed *speed);
+       int (*get_max_lnk_width)(struct slot *slot, enum pcie_link_width *val);
+       int (*get_cur_lnk_width)(struct slot *slot, enum pcie_link_width *val);
+       int (*query_power_fault)(struct slot *slot);
+       void (*green_led_on)(struct slot *slot);
+       void (*green_led_off)(struct slot *slot);
+       void (*green_led_blink)(struct slot *slot);
+       void (*release_ctlr)(struct controller *ctrl);
+       int (*check_lnk_status)(struct controller *ctrl);
 };
 
-
 #ifdef CONFIG_ACPI
 #include <acpi/acpi.h>
 #include <acpi/acpi_bus.h>
 #include <acpi/actypes.h>
 #include <linux/pci-acpi.h>
 
-#define pciehp_get_hp_hw_control_from_firmware(dev) \
+#define pciehp_get_hp_hw_control_from_firmware(dev)                    \
        pciehp_acpi_get_hp_hw_control_from_firmware(dev)
 static inline int pciehp_get_hp_params_from_firmware(struct pci_dev *dev,
                        struct hotplug_params *hpp)
index f13f313..a92eda6 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/pci.h>
 #include "pciehp.h"
 #include <linux/interrupt.h>
+#include <linux/time.h>
 
 /* Global variables */
 int pciehp_debug;
@@ -87,6 +88,95 @@ static struct hotplug_slot_ops pciehp_hotplug_slot_ops = {
        .get_cur_bus_speed =    get_cur_bus_speed,
 };
 
+/*
+ * Check the status of the Electro Mechanical Interlock (EMI)
+ */
+static int get_lock_status(struct hotplug_slot *hotplug_slot, u8 *value)
+{
+       struct slot *slot = hotplug_slot->private;
+       return (slot->hpc_ops->get_emi_status(slot, value));
+}
+
+/*
+ * sysfs interface for the Electro Mechanical Interlock (EMI)
+ * 1 == locked, 0 == unlocked
+ */
+static ssize_t lock_read_file(struct hotplug_slot *slot, char *buf)
+{
+       int retval;
+       u8 value;
+
+       retval = get_lock_status(slot, &value);
+       if (retval)
+               goto lock_read_exit;
+       retval = sprintf (buf, "%d\n", value);
+
+lock_read_exit:
+       return retval;
+}
+
+/*
+ * Change the status of the Electro Mechanical Interlock (EMI)
+ * This is a toggle - in addition there must be at least 1 second
+ * in between toggles.
+ */
+static int set_lock_status(struct hotplug_slot *hotplug_slot, u8 status)
+{
+       struct slot *slot = hotplug_slot->private;
+       int retval;
+       u8 value;
+
+       mutex_lock(&slot->ctrl->crit_sect);
+
+       /* has it been >1 sec since our last toggle? */
+       if ((get_seconds() - slot->last_emi_toggle) < 1)
+               return -EINVAL;
+
+       /* see what our current state is */
+       retval = get_lock_status(hotplug_slot, &value);
+       if (retval || (value == status))
+               goto set_lock_exit;
+
+       slot->hpc_ops->toggle_emi(slot);
+set_lock_exit:
+       mutex_unlock(&slot->ctrl->crit_sect);
+       return 0;
+}
+
+/*
+ * sysfs interface which allows the user to toggle the Electro Mechanical
+ * Interlock.  Valid values are either 0 or 1.  0 == unlock, 1 == lock
+ */
+static ssize_t lock_write_file(struct hotplug_slot *slot, const char *buf,
+               size_t count)
+{
+       unsigned long llock;
+       u8 lock;
+       int retval = 0;
+
+       llock = simple_strtoul(buf, NULL, 10);
+       lock = (u8)(llock & 0xff);
+
+       switch (lock) {
+               case 0:
+               case 1:
+                       retval = set_lock_status(slot, lock);
+                       break;
+               default:
+                       err ("%d is an invalid lock value\n", lock);
+                       retval = -EINVAL;
+       }
+       if (retval)
+               return retval;
+       return count;
+}
+
+static struct hotplug_slot_attribute hotplug_slot_attr_lock = {
+       .attr = {.name = "lock", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+       .show = lock_read_file,
+       .store = lock_write_file
+};
+
 /**
  * release_slot - free up the memory used by a slot
  * @hotplug_slot: slot to free
@@ -98,148 +188,108 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
        dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
 
        kfree(slot->hotplug_slot->info);
-       kfree(slot->hotplug_slot->name);
        kfree(slot->hotplug_slot);
        kfree(slot);
 }
 
+static void make_slot_name(struct slot *slot)
+{
+       snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "%04d_%04d",
+                slot->bus, slot->number);
+}
+
 static int init_slots(struct controller *ctrl)
 {
        struct slot *slot;
-       struct hpc_ops *hpc_ops;
        struct hotplug_slot *hotplug_slot;
-       struct hotplug_slot_info *hotplug_slot_info;
-       u8 number_of_slots;
-       u8 slot_device;
-       u32 slot_number;
-       int result = -ENOMEM;
+       struct hotplug_slot_info *info;
+       int retval = -ENOMEM;
+       int i;
 
-       number_of_slots = ctrl->num_slots;
-       slot_device = ctrl->slot_device_offset;
-       slot_number = ctrl->first_slot;
-
-       while (number_of_slots) {
+       for (i = 0; i < ctrl->num_slots; i++) {
                slot = kzalloc(sizeof(*slot), GFP_KERNEL);
                if (!slot)
                        goto error;
 
-               slot->hotplug_slot =
-                               kzalloc(sizeof(*(slot->hotplug_slot)),
-                                               GFP_KERNEL);
-               if (!slot->hotplug_slot)
+               hotplug_slot = kzalloc(sizeof(*hotplug_slot), GFP_KERNEL);
+               if (!hotplug_slot)
                        goto error_slot;
-               hotplug_slot = slot->hotplug_slot;
+               slot->hotplug_slot = hotplug_slot;
 
-               hotplug_slot->info =
-                       kzalloc(sizeof(*(hotplug_slot->info)),
-                                               GFP_KERNEL);
-               if (!hotplug_slot->info)
+               info = kzalloc(sizeof(*info), GFP_KERNEL);
+               if (!info)
                        goto error_hpslot;
-               hotplug_slot_info = hotplug_slot->info;
-               hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
-               if (!hotplug_slot->name)
-                       goto error_info;
+               hotplug_slot->info = info;
 
-               slot->ctrl = ctrl;
-               slot->bus = ctrl->slot_bus;
-               slot->device = slot_device;
-               slot->hpc_ops = hpc_ops = ctrl->hpc_ops;
+               hotplug_slot->name = slot->name;
 
+               slot->hp_slot = i;
+               slot->ctrl = ctrl;
+               slot->bus = ctrl->pci_dev->subordinate->number;
+               slot->device = ctrl->slot_device_offset + i;
+               slot->hpc_ops = ctrl->hpc_ops;
                slot->number = ctrl->first_slot;
-               slot->hp_slot = slot_device - ctrl->slot_device_offset;
 
                /* register this slot with the hotplug pci core */
                hotplug_slot->private = slot;
                hotplug_slot->release = &release_slot;
-               make_slot_name(hotplug_slot->name, SLOT_NAME_SIZE, slot);
+               make_slot_name(slot);
                hotplug_slot->ops = &pciehp_hotplug_slot_ops;
 
-               hpc_ops->get_power_status(slot,
-                       &(hotplug_slot_info->power_status));
-               hpc_ops->get_attention_status(slot,
-                       &(hotplug_slot_info->attention_status));
-               hpc_ops->get_latch_status(slot,
-                       &(hotplug_slot_info->latch_status));
-               hpc_ops->get_adapter_status(slot,
-                       &(hotplug_slot_info->adapter_status));
+               get_power_status(hotplug_slot, &info->power_status);
+               get_attention_status(hotplug_slot, &info->attention_status);
+               get_latch_status(hotplug_slot, &info->latch_status);
+               get_adapter_status(hotplug_slot, &info->adapter_status);
 
                dbg("Registering bus=%x dev=%x hp_slot=%x sun=%x "
-                       "slot_device_offset=%x\n",
-                       slot->bus, slot->device, slot->hp_slot, slot->number,
-                       ctrl->slot_device_offset);
-               result = pci_hp_register(hotplug_slot);
-               if (result) {
-                       err ("pci_hp_register failed with error %d\n", result);
-                       goto error_name;
+                   "slot_device_offset=%x\n", slot->bus, slot->device,
+                   slot->hp_slot, slot->number, ctrl->slot_device_offset);
+               retval = pci_hp_register(hotplug_slot);
+               if (retval) {
+                       err ("pci_hp_register failed with error %d\n", retval);
+                       goto error_info;
+               }
+               /* create additional sysfs entries */
+               if (EMI(ctrl->ctrlcap)) {
+                       retval = sysfs_create_file(&hotplug_slot->kobj,
+                               &hotplug_slot_attr_lock.attr);
+                       if (retval) {
+                               pci_hp_deregister(hotplug_slot);
+                               err("cannot create additional sysfs entries\n");
+                               goto error_info;
+                       }
                }
 
-               slot->next = ctrl->slot;
-               ctrl->slot = slot;
-
-               number_of_slots--;
-               slot_device++;
-               slot_number += ctrl->slot_num_inc;
+               list_add(&slot->slot_list, &ctrl->slot_list);
        }
 
        return 0;
-
-error_name:
-       kfree(hotplug_slot->name);
 error_info:
-       kfree(hotplug_slot_info);
+       kfree(info);
 error_hpslot:
        kfree(hotplug_slot);
 error_slot:
        kfree(slot);
 error:
-       return result;
-}
-
-
-static int cleanup_slots (struct controller * ctrl)
-{
-       struct slot *old_slot, *next_slot;
-
-       old_slot = ctrl->slot;
-       ctrl->slot = NULL;
-
-       while (old_slot) {
-               next_slot = old_slot->next;
-               pci_hp_deregister (old_slot->hotplug_slot);
-               old_slot = next_slot;
-       }
-
-
-       return(0);
+       return retval;
 }
 
-static int get_ctlr_slot_config(struct controller *ctrl)
+static void cleanup_slots(struct controller *ctrl)
 {
-       int num_ctlr_slots;             /* Not needed; PCI Express has 1 slot per port*/
-       int first_device_num;           /* Not needed */
-       int physical_slot_num;
-       u8 ctrlcap;                     
-       int rc;
+       struct list_head *tmp;
+       struct list_head *next;
+       struct slot *slot;
 
-       rc = pcie_get_ctlr_slot_config(ctrl, &num_ctlr_slots, &first_device_num, &physical_slot_num, &ctrlcap);
-       if (rc) {
-               err("%s: get_ctlr_slot_config fail for b:d (%x:%x)\n", __FUNCTION__, ctrl->bus, ctrl->device);
-               return (-1);
+       list_for_each_safe(tmp, next, &ctrl->slot_list) {
+               slot = list_entry(tmp, struct slot, slot_list);
+               list_del(&slot->slot_list);
+               if (EMI(ctrl->ctrlcap))
+                       sysfs_remove_file(&slot->hotplug_slot->kobj,
+                               &hotplug_slot_attr_lock.attr);
+               pci_hp_deregister(slot->hotplug_slot);
        }
-
-       ctrl->num_slots = num_ctlr_slots;       /* PCI Express has 1 slot per port */
-       ctrl->slot_device_offset = first_device_num;
-       ctrl->first_slot = physical_slot_num;
-       ctrl->ctrlcap = ctrlcap;        
-
-       dbg("%s: bus(0x%x) num_slot(0x%x) 1st_dev(0x%x) psn(0x%x) ctrlcap(%x) for b:d (%x:%x)\n",
-               __FUNCTION__, ctrl->slot_bus, num_ctlr_slots, first_device_num, physical_slot_num, ctrlcap, 
-               ctrl->bus, ctrl->device);
-
-       return (0);
 }
 
-
 /*
  * set_attention_status - Turns the Amber LED for a slot on, off or blink
  */
@@ -378,8 +428,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
        int rc;
        struct controller *ctrl;
        struct slot *t_slot;
-       int first_device_num = 0 ;      /* first PCI device number supported by this PCIE */  
-       int num_ctlr_slots;             /* number of slots supported by this HPC */
        u8 value;
        struct pci_dev *pdev;
        
@@ -388,6 +436,7 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
                err("%s : out of memory\n", __FUNCTION__);
                goto err_out_none;
        }
+       INIT_LIST_HEAD(&ctrl->slot_list);
 
        pdev = dev->port;
        ctrl->pci_dev = pdev;
@@ -400,13 +449,6 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
 
        pci_set_drvdata(pdev, ctrl);
 
-       ctrl->pci_bus = kmalloc(sizeof(*ctrl->pci_bus), GFP_KERNEL);
-       if (!ctrl->pci_bus) {
-               err("%s: out of memory\n", __FUNCTION__);
-               rc = -ENOMEM;
-               goto err_out_unmap_mmio_region;
-       }
-       memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus));
        ctrl->bus = pdev->bus->number;  /* ctrl bus */
        ctrl->slot_bus = pdev->subordinate->number;  /* bus controlled by this HPC */
 
@@ -415,26 +457,14 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
        dbg("%s: ctrl bus=0x%x, device=%x, function=%x, irq=%x\n", __FUNCTION__,
                ctrl->bus, ctrl->device, ctrl->function, pdev->irq);
 
-       /*
-        *      Save configuration headers for this and subordinate PCI buses
-        */
-
-       rc = get_ctlr_slot_config(ctrl);
-       if (rc) {
-               err(msg_initialization_err, rc);
-               goto err_out_free_ctrl_bus;
-       }
-       first_device_num = ctrl->slot_device_offset;
-       num_ctlr_slots = ctrl->num_slots; 
-
        /* Setup the slot information structures */
        rc = init_slots(ctrl);
        if (rc) {
-               err(msg_initialization_err, 6);
-               goto err_out_free_ctrl_slot;
+               err("%s: slot initialization failed\n", PCIE_MODULE_NAME);
+               goto err_out_release_ctlr;
        }
 
-       t_slot = pciehp_find_slot(ctrl, first_device_num);
+       t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
 
        /*      Finish setting up the hot plug ctrl device */
        ctrl->next_event = 0;
@@ -447,32 +477,18 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
                pciehp_ctrl_list = ctrl;
        }
 
-       /* Wait for exclusive access to hardware */
-       mutex_lock(&ctrl->ctrl_lock);
-
        t_slot->hpc_ops->get_adapter_status(t_slot, &value); /* Check if slot is occupied */
-       
        if ((POWER_CTRL(ctrl->ctrlcap)) && !value) {
                rc = t_slot->hpc_ops->power_off_slot(t_slot); /* Power off slot if not occupied*/
-               if (rc) {
-                       /* Done with exclusive hardware access */
-                       mutex_unlock(&ctrl->ctrl_lock);
+               if (rc)
                        goto err_out_free_ctrl_slot;
-               } else
-                       /* Wait for the command to complete */
-                       wait_for_ctrl_irq (ctrl);
        }
 
-       /* Done with exclusive hardware access */
-       mutex_unlock(&ctrl->ctrl_lock);
-
        return 0;
 
 err_out_free_ctrl_slot:
        cleanup_slots(ctrl);
-err_out_free_ctrl_bus:
-       kfree(ctrl->pci_bus);
-err_out_unmap_mmio_region:
+err_out_release_ctlr:
        ctrl->hpc_ops->release_ctlr(ctrl);
 err_out_free_ctrl:
        kfree(ctrl);
@@ -506,8 +522,6 @@ static void __exit unload_pciehpd(void)
        while (ctrl) {
                cleanup_slots(ctrl);
 
-               kfree (ctrl->pci_bus);
-
                ctrl->hpc_ops->release_ctlr(ctrl);
 
                tctrl = ctrl;
index 372c63e..4283ef5 100644 (file)
@@ -48,9 +48,8 @@ static inline char *slot_name(struct slot *p_slot)
        return p_slot->hotplug_slot->name;
 }
 
-u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
 {
-       struct controller *ctrl = (struct controller *) inst_id;
        struct slot *p_slot;
        u8 rc = 0;
        u8 getstatus;
@@ -101,9 +100,8 @@ u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
 
 }
 
-u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
 {
-       struct controller *ctrl = (struct controller *) inst_id;
        struct slot *p_slot;
        u8 rc = 0;
        u8 getstatus;
@@ -143,9 +141,8 @@ u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
        return rc;
 }
 
-u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
 {
-       struct controller *ctrl = (struct controller *) inst_id;
        struct slot *p_slot;
        u8 presence_save, rc = 0;
        struct event_info *taskInfo;
@@ -187,9 +184,8 @@ u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
        return rc;
 }
 
-u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
+u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
 {
-       struct controller *ctrl = (struct controller *) inst_id;
        struct slot *p_slot;
        u8 rc = 0;
        struct event_info *taskInfo;
@@ -233,35 +229,25 @@ u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
 
 static void set_slot_off(struct controller *ctrl, struct slot * pslot)
 {
-       /* Wait for exclusive access to hardware */
-       mutex_lock(&ctrl->ctrl_lock);
-
        /* turn off slot, turn on Amber LED, turn off Green LED if supported*/
        if (POWER_CTRL(ctrl->ctrlcap)) {
                if (pslot->hpc_ops->power_off_slot(pslot)) {   
-                       err("%s: Issue of Slot Power Off command failed\n", __FUNCTION__);
-                       mutex_unlock(&ctrl->ctrl_lock);
+                       err("%s: Issue of Slot Power Off command failed\n",
+                           __FUNCTION__);
                        return;
                }
-               wait_for_ctrl_irq (ctrl);
        }
 
-       if (PWR_LED(ctrl->ctrlcap)) {
+       if (PWR_LED(ctrl->ctrlcap))
                pslot->hpc_ops->green_led_off(pslot);   
-               wait_for_ctrl_irq (ctrl);
-       }
 
-       if (ATTN_LED(ctrl->ctrlcap)) { 
-               if (pslot->hpc_ops->set_attention_status(pslot, 1)) {   
-                       err("%s: Issue of Set Attention Led command failed\n", __FUNCTION__);
-                       mutex_unlock(&ctrl->ctrl_lock);
+       if (ATTN_LED(ctrl->ctrlcap)) {
+               if (pslot->hpc_ops->set_attention_status(pslot, 1)) {
+                       err("%s: Issue of Set Attention Led command failed\n",
+                           __FUNCTION__);
                        return;
                }
-               wait_for_ctrl_irq (ctrl);
        }
-
-       /* Done with exclusive hardware access */
-       mutex_unlock(&ctrl->ctrl_lock);
 }
 
 /**
@@ -274,7 +260,7 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
 static int board_added(struct slot *p_slot)
 {
        u8 hp_slot;
-       int rc = 0;
+       int retval = 0;
        struct controller *ctrl = p_slot->ctrl;
 
        hp_slot = p_slot->device - ctrl->slot_device_offset;
@@ -283,53 +269,38 @@ static int board_added(struct slot *p_slot)
                        __FUNCTION__, p_slot->device,
                        ctrl->slot_device_offset, hp_slot);
 
-       /* Wait for exclusive access to hardware */
-       mutex_lock(&ctrl->ctrl_lock);
-
        if (POWER_CTRL(ctrl->ctrlcap)) {
                /* Power on slot */
-               rc = p_slot->hpc_ops->power_on_slot(p_slot);
-               if (rc) {
-                       mutex_unlock(&ctrl->ctrl_lock);
-                       return -1;
-               }
-
-               /* Wait for the command to complete */
-               wait_for_ctrl_irq (ctrl);
+               retval = p_slot->hpc_ops->power_on_slot(p_slot);
+               if (retval)
+                       return retval;
        }
        
-       if (PWR_LED(ctrl->ctrlcap)) {
+       if (PWR_LED(ctrl->ctrlcap))
                p_slot->hpc_ops->green_led_blink(p_slot);
-                       
-               /* Wait for the command to complete */
-               wait_for_ctrl_irq (ctrl);
-       }
-
-       /* Done with exclusive hardware access */
-       mutex_unlock(&ctrl->ctrl_lock);
 
        /* Wait for ~1 second */
-       wait_for_ctrl_irq (ctrl);
+       msleep(1000);
 
-       /*  Check link training status */
-       rc = p_slot->hpc_ops->check_lnk_status(ctrl);  
-       if (rc) {
+       /* Check link training status */
+       retval = p_slot->hpc_ops->check_lnk_status(ctrl);
+       if (retval) {
                err("%s: Failed to check link status\n", __FUNCTION__);
                set_slot_off(ctrl, p_slot);
-               return rc;
+               return retval;
        }
 
        /* Check for a power fault */
        if (p_slot->hpc_ops->query_power_fault(p_slot)) {
                dbg("%s: power fault detected\n", __FUNCTION__);
-               rc = POWER_FAILURE;
+               retval = POWER_FAILURE;
                goto err_exit;
        }
 
-       rc = pciehp_configure_device(p_slot);
-       if (rc) {
+       retval = pciehp_configure_device(p_slot);
+       if (retval) {
                err("Cannot add device 0x%x:%x\n", p_slot->bus,
-                               p_slot->device);
+                   p_slot->device);
                goto err_exit;
        }
 
@@ -338,26 +309,16 @@ static int board_added(struct slot *p_slot)
         */
        if (pcie_mch_quirk)
                pci_fixup_device(pci_fixup_final, ctrl->pci_dev);
-       if (PWR_LED(ctrl->ctrlcap)) {
-               /* Wait for exclusive access to hardware */
-               mutex_lock(&ctrl->ctrl_lock);
-
+       if (PWR_LED(ctrl->ctrlcap))
                p_slot->hpc_ops->green_led_on(p_slot);
-  
-               /* Wait for the command to complete */
-               wait_for_ctrl_irq (ctrl);
-       
-               /* Done with exclusive hardware access */
-               mutex_unlock(&ctrl->ctrl_lock);
-       }
+
        return 0;
 
 err_exit:
        set_slot_off(ctrl, p_slot);
-       return -1;
+       return retval;
 }
 
-
 /**
  * remove_board - Turns off slot and LED's
  *
@@ -366,44 +327,32 @@ static int remove_board(struct slot *p_slot)
 {
        u8 device;
        u8 hp_slot;
-       int rc;
+       int retval = 0;
        struct controller *ctrl = p_slot->ctrl;
 
-       if (pciehp_unconfigure_device(p_slot))
-               return 1;
+       retval = pciehp_unconfigure_device(p_slot);
+       if (retval)
+               return retval;
 
        device = p_slot->device;
-
        hp_slot = p_slot->device - ctrl->slot_device_offset;
        p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
        dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);
 
-       /* Wait for exclusive access to hardware */
-       mutex_lock(&ctrl->ctrl_lock);
-
        if (POWER_CTRL(ctrl->ctrlcap)) {
                /* power off slot */
-               rc = p_slot->hpc_ops->power_off_slot(p_slot);
-               if (rc) {
-                       err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
-                       mutex_unlock(&ctrl->ctrl_lock);
-                       return rc;
+               retval = p_slot->hpc_ops->power_off_slot(p_slot);
+               if (retval) {
+                       err("%s: Issue of Slot Disable command failed\n",
+                           __FUNCTION__);
+                       return retval;
                }
-               /* Wait for the command to complete */
-               wait_for_ctrl_irq (ctrl);
        }
 
-       if (PWR_LED(ctrl->ctrlcap)) {
+       if (PWR_LED(ctrl->ctrlcap))
                /* turn off Green LED */
                p_slot->hpc_ops->green_led_off(p_slot);
-       
-               /* Wait for the command to complete */
-               wait_for_ctrl_irq (ctrl);
-       }
-
-       /* Done with exclusive hardware access */
-       mutex_unlock(&ctrl->ctrl_lock);
 
        return 0;
 }
@@ -448,18 +397,10 @@ static void pciehp_pushbutton_thread(unsigned long slot)
                dbg("%s: adding bus:device(%x:%x)\n", __FUNCTION__,
                                p_slot->bus, p_slot->device);
 
-               if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
-                       /* Wait for exclusive access to hardware */
-                       mutex_lock(&p_slot->ctrl->ctrl_lock);
-
+               if (pciehp_enable_slot(p_slot) &&
+                   PWR_LED(p_slot->ctrl->ctrlcap))
                        p_slot->hpc_ops->green_led_off(p_slot);
 
-                       /* Wait for the command to complete */
-                       wait_for_ctrl_irq (p_slot->ctrl);
-
-                       /* Done with exclusive hardware access */
-                       mutex_unlock(&p_slot->ctrl->ctrl_lock);
-               }
                p_slot->state = STATIC_STATE;
        }
 
@@ -498,18 +439,10 @@ static void pciehp_surprise_rm_thread(unsigned long slot)
                dbg("%s: adding bus:device(%x:%x)\n",
                                __FUNCTION__, p_slot->bus, p_slot->device);
 
-               if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl->ctrlcap)) {
-                       /* Wait for exclusive access to hardware */
-                       mutex_lock(&p_slot->ctrl->ctrl_lock);
-
+               if (pciehp_enable_slot(p_slot) &&
+                   PWR_LED(p_slot->ctrl->ctrlcap))
                        p_slot->hpc_ops->green_led_off(p_slot);
 
-                       /* Wait for the command to complete */
-                       wait_for_ctrl_irq (p_slot->ctrl);
-
-                       /* Done with exclusive hardware access */
-                       mutex_unlock(&p_slot->ctrl->ctrl_lock);
-               }
                p_slot->state = STATIC_STATE;
        }
 
@@ -620,46 +553,24 @@ static void interrupt_event_handler(struct controller *ctrl)
 
                                        switch (p_slot->state) {
                                        case BLINKINGOFF_STATE:
-                                               /* Wait for exclusive access to hardware */
-                                               mutex_lock(&ctrl->ctrl_lock);
-                                               
-                                               if (PWR_LED(ctrl->ctrlcap)) {
+                                               if (PWR_LED(ctrl->ctrlcap))
                                                        p_slot->hpc_ops->green_led_on(p_slot);
-                                                       /* Wait for the command to complete */
-                                                       wait_for_ctrl_irq (ctrl);
-                                               }
-                                               if (ATTN_LED(ctrl->ctrlcap)) {
-                                                       p_slot->hpc_ops->set_attention_status(p_slot, 0);
 
-                                                       /* Wait for the command to complete */
-                                                       wait_for_ctrl_irq (ctrl);
-                                               }
-                                               /* Done with exclusive hardware access */
-                                               mutex_unlock(&ctrl->ctrl_lock);
+                                               if (ATTN_LED(ctrl->ctrlcap))
+                                                       p_slot->hpc_ops->set_attention_status(p_slot, 0);
                                                break;
                                        case BLINKINGON_STATE:
-                                               /* Wait for exclusive access to hardware */
-                                               mutex_lock(&ctrl->ctrl_lock);
-
-                                               if (PWR_LED(ctrl->ctrlcap)) {
+                                               if (PWR_LED(ctrl->ctrlcap))
                                                        p_slot->hpc_ops->green_led_off(p_slot);
-                                                       /* Wait for the command to complete */
-                                                       wait_for_ctrl_irq (ctrl);
-                                               }
-                                               if (ATTN_LED(ctrl->ctrlcap)){
-                                                       p_slot->hpc_ops->set_attention_status(p_slot, 0);
-                                                       /* Wait for the command to complete */
-                                                       wait_for_ctrl_irq (ctrl);
-                                               }
-                                               /* Done with exclusive hardware access */
-                                               mutex_unlock(&ctrl->ctrl_lock);
 
+                                               if (ATTN_LED(ctrl->ctrlcap))
+                                                       p_slot->hpc_ops->set_attention_status(p_slot, 0);
                                                break;
                                        default:
                                                warn("Not a valid state\n");
                                                return;
                                        }
-                                       info(msg_button_cancel, slot_name(p_slot));
+                                       info("PCI slot #%s - action canceled due to button press.\n", slot_name(p_slot));
                                        p_slot->state = STATIC_STATE;
                                }
                                /* ***********Button Pressed (No action on 1st press...) */
@@ -672,34 +583,21 @@ static void interrupt_event_handler(struct controller *ctrl)
                                                        /* slot is on */
                                                        dbg("slot is on\n");
                                                        p_slot->state = BLINKINGOFF_STATE;
-                                                       info(msg_button_off, slot_name(p_slot));
+                                                       info("PCI slot #%s - powering off due to button press.\n", slot_name(p_slot));
                                                } else {
                                                        /* slot is off */
                                                        dbg("slot is off\n");
                                                        p_slot->state = BLINKINGON_STATE;
-                                                       info(msg_button_on, slot_name(p_slot));
+                                                       info("PCI slot #%s - powering on due to button press.\n", slot_name(p_slot));
                                                }
 
-                                               /* Wait for exclusive access to hardware */
-                                               mutex_lock(&ctrl->ctrl_lock);
-
                                                /* blink green LED and turn off amber */
-                                               if (PWR_LED(ctrl->ctrlcap)) {
+                                               if (PWR_LED(ctrl->ctrlcap))
                                                        p_slot->hpc_ops->green_led_blink(p_slot);
-                                                       /* Wait for the command to complete */
-                                                       wait_for_ctrl_irq (ctrl);
-                                               }
 
-                                               if (ATTN_LED(ctrl->ctrlcap)) {
+                                               if (ATTN_LED(ctrl->ctrlcap))
                                                        p_slot->hpc_ops->set_attention_status(p_slot, 0);
 
-                                                       /* Wait for the command to complete */
-                                                       wait_for_ctrl_irq (ctrl);
-                                               }
-
-                                               /* Done with exclusive hardware access */
-                                               mutex_unlock(&ctrl->ctrl_lock);
-
                                                init_timer(&p_slot->task_event);
                                                p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
                                                p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
@@ -712,21 +610,11 @@ static void interrupt_event_handler(struct controller *ctrl)
                                else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
                                        if (POWER_CTRL(ctrl->ctrlcap)) {
                                                dbg("power fault\n");
-                                               /* Wait for exclusive access to hardware */
-                                               mutex_lock(&ctrl->ctrl_lock);
-
-                                               if (ATTN_LED(ctrl->ctrlcap)) {
+                                               if (ATTN_LED(ctrl->ctrlcap))
                                                        p_slot->hpc_ops->set_attention_status(p_slot, 1);
-                                                       wait_for_ctrl_irq (ctrl);
-                                               }
 
-                                               if (PWR_LED(ctrl->ctrlcap)) {
+                                               if (PWR_LED(ctrl->ctrlcap))
                                                        p_slot->hpc_ops->green_led_off(p_slot);
-                                                       wait_for_ctrl_irq (ctrl);
-                                               }
-
-                                               /* Done with exclusive hardware access */
-                                               mutex_unlock(&ctrl->ctrl_lock);
                                        }
                                }
                                /***********SURPRISE REMOVAL********************/
@@ -754,7 +642,6 @@ static void interrupt_event_handler(struct controller *ctrl)
        }
 }
 
-
 int pciehp_enable_slot(struct slot *p_slot)
 {
        u8 getstatus = 0;
index 25d3aad..fbc64aa 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/timer.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
+#include <linux/time.h>
 
 #include "../pci.h"
 #include "pciehp.h"
@@ -105,34 +106,30 @@ enum ctrl_offsets {
        ROOTCTRL        =       offsetof(struct ctrl_reg, root_ctrl),
        ROOTSTATUS      =       offsetof(struct ctrl_reg, root_status),
 };
-static int pcie_cap_base = 0;          /* Base of the PCI Express capability item structure */ 
-
-#define PCIE_CAP_ID(cb)        ( cb + PCIECAPID )
-#define NXT_CAP_PTR(cb)        ( cb + NXTCAPPTR )
-#define CAP_REG(cb)    ( cb + CAPREG )
-#define DEV_CAP(cb)    ( cb + DEVCAP )
-#define DEV_CTRL(cb)   ( cb + DEVCTRL )
-#define DEV_STATUS(cb) ( cb + DEVSTATUS )
-#define LNK_CAP(cb)    ( cb + LNKCAP )
-#define LNK_CTRL(cb)   ( cb + LNKCTRL )
-#define LNK_STATUS(cb) ( cb + LNKSTATUS )
-#define SLOT_CAP(cb)   ( cb + SLOTCAP )
-#define SLOT_CTRL(cb)  ( cb + SLOTCTRL )
-#define SLOT_STATUS(cb)        ( cb + SLOTSTATUS )
-#define ROOT_CTRL(cb)  ( cb + ROOTCTRL )
-#define ROOT_STATUS(cb)        ( cb + ROOTSTATUS )
-
-#define hp_register_read_word(pdev, reg , value)               \
-       pci_read_config_word(pdev, reg, &value)
-
-#define hp_register_read_dword(pdev, reg , value)              \
-       pci_read_config_dword(pdev, reg, &value)
-#define hp_register_write_word(pdev, reg , value)              \
-       pci_write_config_word(pdev, reg, value)
-
-#define hp_register_dwrite_word(pdev, reg , value)             \
-       pci_write_config_dword(pdev, reg, value)
+
+static inline int pciehp_readw(struct controller *ctrl, int reg, u16 *value)
+{
+       struct pci_dev *dev = ctrl->pci_dev;
+       return pci_read_config_word(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_readl(struct controller *ctrl, int reg, u32 *value)
+{
+       struct pci_dev *dev = ctrl->pci_dev;
+       return pci_read_config_dword(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_writew(struct controller *ctrl, int reg, u16 value)
+{
+       struct pci_dev *dev = ctrl->pci_dev;
+       return pci_write_config_word(dev, ctrl->cap_base + reg, value);
+}
+
+static inline int pciehp_writel(struct controller *ctrl, int reg, u32 value)
+{
+       struct pci_dev *dev = ctrl->pci_dev;
+       return pci_write_config_dword(dev, ctrl->cap_base + reg, value);
+}
 
 /* Field definitions in PCI Express Capabilities Register */
 #define CAP_VER                        0x000F
@@ -196,6 +193,7 @@ static int pcie_cap_base = 0;               /* Base of the PCI Express capability item struct
 #define ATTN_LED_CTRL                  0x00C0
 #define PWR_LED_CTRL                   0x0300
 #define PWR_CTRL                       0x0400
+#define EMI_CTRL                       0x0800
 
 /* Attention indicator and Power indicator states */
 #define LED_ON         0x01
@@ -206,6 +204,10 @@ static int pcie_cap_base = 0;              /* Base of the PCI Express capability item struct
 #define POWER_ON       0
 #define POWER_OFF      0x0400
 
+/* EMI Status defines */
+#define EMI_DISENGAGED 0
+#define EMI_ENGAGED    1
+
 /* Field definitions in Slot Status Register */
 #define ATTN_BUTTN_PRESSED     0x0001
 #define PWR_FAULT_DETECTED     0x0002
@@ -214,114 +216,117 @@ static int pcie_cap_base = 0;           /* Base of the PCI Express capability item struct
 #define CMD_COMPLETED          0x0010
 #define MRL_STATE              0x0020
 #define PRSN_STATE             0x0040
+#define EMI_STATE              0x0080
+#define EMI_STATUS_BIT         7
 
 static spinlock_t hpc_event_lock;
 
 DEFINE_DBG_BUFFER              /* Debug string buffer for entire HPC defined here */
-static struct php_ctlr_state_s *php_ctlr_list_head; /* HPC state linked list */
 static int ctlr_seq_num = 0;   /* Controller sequence # */
-static spinlock_t list_lock;
-
-static irqreturn_t pcie_isr(int IRQ, void *dev_id);
 
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds);
+static irqreturn_t pcie_isr(int irq, void *dev_id);
+static void start_int_poll_timer(struct controller *ctrl, int sec);
 
 /* This is the interrupt polling timeout function. */
-static void int_poll_timeout(unsigned long lphp_ctlr)
+static void int_poll_timeout(unsigned long data)
 {
-       struct php_ctlr_state_s *php_ctlr = (struct php_ctlr_state_s *)lphp_ctlr;
+       struct controller *ctrl = (struct controller *)data;
 
        DBG_ENTER_ROUTINE
 
-       if ( !php_ctlr ) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return;
-       }
-
        /* Poll for interrupt events.  regs == NULL => polling */
-       pcie_isr( 0, (void *)php_ctlr );
-
-       init_timer(&php_ctlr->int_poll_timer);
+       pcie_isr(0, ctrl);
 
+       init_timer(&ctrl->poll_timer);
        if (!pciehp_poll_time)
                pciehp_poll_time = 2; /* reset timer to poll in 2 secs if user doesn't specify at module installation*/
 
-       start_int_poll_timer(php_ctlr, pciehp_poll_time);  
-       
-       return;
+       start_int_poll_timer(ctrl, pciehp_poll_time);
 }
 
 /* This function starts the interrupt polling timer. */
-static void start_int_poll_timer(struct php_ctlr_state_s *php_ctlr, int seconds)
+static void start_int_poll_timer(struct controller *ctrl, int sec)
 {
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return;
-       }
+       /* Clamp to sane value */
+       if ((sec <= 0) || (sec > 60))
+               sec = 2;
+
+       ctrl->poll_timer.function = &int_poll_timeout;
+       ctrl->poll_timer.data = (unsigned long)ctrl;
+       ctrl->poll_timer.expires = jiffies + sec * HZ;
+       add_timer(&ctrl->poll_timer);
+}
 
-       if ( ( seconds <= 0 ) || ( seconds > 60 ) )
-               seconds = 2;            /* Clamp to sane value */
+static inline int pcie_wait_cmd(struct controller *ctrl)
+{
+       int retval = 0;
+       unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
+       unsigned long timeout = msecs_to_jiffies(msecs);
+       int rc;
 
-       php_ctlr->int_poll_timer.function = &int_poll_timeout;
-       php_ctlr->int_poll_timer.data = (unsigned long)php_ctlr;    /* Instance data */
-       php_ctlr->int_poll_timer.expires = jiffies + seconds * HZ;
-       add_timer(&php_ctlr->int_poll_timer);
+       rc = wait_event_interruptible_timeout(ctrl->queue,
+                                             !ctrl->cmd_busy, timeout);
+       if (!rc)
+               dbg("Command not completed in 1000 msec\n");
+       else if (rc < 0) {
+               retval = -EINTR;
+               info("Command was interrupted by a signal\n");
+       }
 
-       return;
+       return retval;
 }
 
 static int pcie_write_cmd(struct slot *slot, u16 cmd)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        int retval = 0;
        u16 slot_status;
 
        DBG_ENTER_ROUTINE 
-       
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
 
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
+       mutex_lock(&ctrl->ctrl_lock);
+
+       retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
        if (retval) {
-                       err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
-                       return retval;
-               }
-       
+               err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+               goto out;
+       }
+
        if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { 
-               /* After 1 sec and CMD_COMPLETED still not set, just proceed forward to issue 
-                  the next command according to spec.  Just print out the error message */
-               dbg("%s : CMD_COMPLETED not clear after 1 sec.\n", __FUNCTION__);
+               /* After 1 sec and CMD_COMPLETED still not set, just
+                  proceed forward to issue the next command according
+                  to spec.  Just print out the error message */
+               dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
+                   __FUNCTION__);
        }
 
-       retval = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), cmd | CMD_CMPL_INTR_ENABLE);
+       ctrl->cmd_busy = 1;
+       retval = pciehp_writew(ctrl, SLOTCTRL, (cmd | CMD_CMPL_INTR_ENABLE));
        if (retval) {
-               err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
-               return retval;
+               err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
+               goto out;
        }
 
+       /*
+        * Wait for command completion.
+        */
+       retval = pcie_wait_cmd(ctrl);
+ out:
+       mutex_unlock(&ctrl->ctrl_lock);
        DBG_LEAVE_ROUTINE 
        return retval;
 }
 
 static int hpc_check_lnk_status(struct controller *ctrl)
 {
-       struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
        u16 lnk_status;
        int retval = 0;
 
        DBG_ENTER_ROUTINE 
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
-       
-       retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(ctrl->cap_base), lnk_status);
-
+       retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
        if (retval) {
-               err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+               err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
                return retval;
        }
 
@@ -340,26 +345,21 @@ static int hpc_check_lnk_status(struct controller *ctrl)
 
 static int hpc_get_attention_status(struct slot *slot, u8 *status)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        u16 slot_ctrl;
        u8 atten_led_state;
        int retval = 0;
        
        DBG_ENTER_ROUTINE 
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
-
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+       retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
        if (retval) {
-               err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
                return retval;
        }
 
-       dbg("%s: SLOT_CTRL %x, value read %x\n", __FUNCTION__,SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+       dbg("%s: SLOTCTRL %x, value read %x\n",
+           __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
 
        atten_led_state = (slot_ctrl & ATTN_LED_CTRL) >> 6;
 
@@ -385,27 +385,22 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
        return 0;
 }
 
-static int hpc_get_power_status(struct slot * slot, u8 *status)
+static int hpc_get_power_status(struct slot *slot, u8 *status)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        u16 slot_ctrl;
        u8 pwr_state;
        int     retval = 0;
        
        DBG_ENTER_ROUTINE 
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
-
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+       retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
        if (retval) {
-               err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
                return retval;
        }
-       dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+       dbg("%s: SLOTCTRL %x value read %x\n",
+           __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
 
        pwr_state = (slot_ctrl & PWR_CTRL) >> 10;
 
@@ -428,21 +423,15 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
 
 static int hpc_get_latch_status(struct slot *slot, u8 *status)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        u16 slot_status;
        int retval = 0;
 
        DBG_ENTER_ROUTINE 
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
-
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+       retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
        if (retval) {
-               err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
                return retval;
        }
 
@@ -454,22 +443,16 @@ static int hpc_get_latch_status(struct slot *slot, u8 *status)
 
 static int hpc_get_adapter_status(struct slot *slot, u8 *status)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        u16 slot_status;
        u8 card_state;
        int retval = 0;
 
        DBG_ENTER_ROUTINE 
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
-
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+       retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
        if (retval) {
-               err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
                return retval;
        }
        card_state = (u8)((slot_status & PRSN_STATE) >> 6);
@@ -479,24 +462,18 @@ static int hpc_get_adapter_status(struct slot *slot, u8 *status)
        return 0;
 }
 
-static int hpc_query_power_fault(struct slot * slot)
+static int hpc_query_power_fault(struct slot *slot)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        u16 slot_status;
        u8 pwr_fault;
        int retval = 0;
 
        DBG_ENTER_ROUTINE 
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
-
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
+       retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
        if (retval) {
-               err("%s : Cannot check for power fault\n", __FUNCTION__);
+               err("%s: Cannot check for power fault\n", __FUNCTION__);
                return retval;
        }
        pwr_fault = (u8)((slot_status & PWR_FAULT_DETECTED) >> 1);
@@ -505,28 +482,63 @@ static int hpc_query_power_fault(struct slot * slot)
        return pwr_fault;
 }
 
-static int hpc_set_attention_status(struct slot *slot, u8 value)
+static int hpc_get_emi_status(struct slot *slot, u8 *status)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
+       u16 slot_status;
+       int retval = 0;
+
+       DBG_ENTER_ROUTINE
+
+       retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+       if (retval) {
+               err("%s : Cannot check EMI status\n", __FUNCTION__);
+               return retval;
+       }
+       *status = (slot_status & EMI_STATE) >> EMI_STATUS_BIT;
+
+       DBG_LEAVE_ROUTINE
+       return retval;
+}
+
+static int hpc_toggle_emi(struct slot *slot)
+{
+       struct controller *ctrl = slot->ctrl;
        u16 slot_cmd = 0;
        u16 slot_ctrl;
        int rc = 0;
 
        DBG_ENTER_ROUTINE
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
+       rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
+       if (rc) {
+               err("%s : hp_register_read_word SLOT_CTRL failed\n",
+                       __FUNCTION__);
+               return rc;
        }
 
-       if (slot->hp_slot >= php_ctlr->num_slots) {
-               err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-               return -1;
-       }
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+       slot_cmd = (slot_ctrl | EMI_CTRL);
+       if (!pciehp_poll_mode)
+               slot_cmd = slot_cmd | HP_INTR_ENABLE;
 
+       pcie_write_cmd(slot, slot_cmd);
+       slot->last_emi_toggle = get_seconds();
+       DBG_LEAVE_ROUTINE
+       return rc;
+}
+
+static int hpc_set_attention_status(struct slot *slot, u8 value)
+{
+       struct controller *ctrl = slot->ctrl;
+       u16 slot_cmd = 0;
+       u16 slot_ctrl;
+       int rc = 0;
+
+       DBG_ENTER_ROUTINE
+
+       rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
        if (rc) {
-               err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
                return rc;
        }
 
@@ -547,7 +559,8 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
                slot_cmd = slot_cmd | HP_INTR_ENABLE; 
 
        pcie_write_cmd(slot, slot_cmd);
-       dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+       dbg("%s: SLOTCTRL %x write cmd %x\n",
+           __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
        
        DBG_LEAVE_ROUTINE
        return rc;
@@ -556,27 +569,16 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
 
 static void hpc_set_green_led_on(struct slot *slot)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        u16 slot_cmd;
        u16 slot_ctrl;
        int rc = 0;
                
        DBG_ENTER_ROUTINE
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return ;
-       }
-
-       if (slot->hp_slot >= php_ctlr->num_slots) {
-               err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-               return ;
-       }
-
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+       rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
        if (rc) {
-               err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
                return;
        }
        slot_cmd = (slot_ctrl & ~PWR_LED_CTRL) | 0x0100;
@@ -585,34 +587,24 @@ static void hpc_set_green_led_on(struct slot *slot)
 
        pcie_write_cmd(slot, slot_cmd);
 
-       dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+       dbg("%s: SLOTCTRL %x write cmd %x\n",
+           __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
        DBG_LEAVE_ROUTINE
        return;
 }
 
 static void hpc_set_green_led_off(struct slot *slot)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        u16 slot_cmd;
        u16 slot_ctrl;
        int rc = 0;
 
        DBG_ENTER_ROUTINE
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return ;
-       }
-
-       if (slot->hp_slot >= php_ctlr->num_slots) {
-               err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-               return ;
-       }
-
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+       rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
        if (rc) {
-               err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
                return;
        }
 
@@ -621,7 +613,8 @@ static void hpc_set_green_led_off(struct slot *slot)
        if (!pciehp_poll_mode)
                slot_cmd = slot_cmd | HP_INTR_ENABLE; 
        pcie_write_cmd(slot, slot_cmd);
-       dbg("%s: SLOT_CTRL %x write cmd %x\n", __FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+       dbg("%s: SLOTCTRL %x write cmd %x\n",
+           __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 
        DBG_LEAVE_ROUTINE
        return;
@@ -629,27 +622,16 @@ static void hpc_set_green_led_off(struct slot *slot)
 
 static void hpc_set_green_led_blink(struct slot *slot)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        u16 slot_cmd;
        u16 slot_ctrl;
        int rc = 0; 
        
        DBG_ENTER_ROUTINE
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return ;
-       }
-
-       if (slot->hp_slot >= php_ctlr->num_slots) {
-               err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-               return ;
-       }
-
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
-
+       rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
        if (rc) {
-               err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
                return;
        }
 
@@ -659,126 +641,54 @@ static void hpc_set_green_led_blink(struct slot *slot)
                slot_cmd = slot_cmd | HP_INTR_ENABLE; 
        pcie_write_cmd(slot, slot_cmd);
 
-       dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+       dbg("%s: SLOTCTRL %x write cmd %x\n",
+           __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
        DBG_LEAVE_ROUTINE
        return;
 }
 
-int pcie_get_ctlr_slot_config(struct controller *ctrl,
-       int *num_ctlr_slots,    /* number of slots in this HPC; only 1 in PCIE  */      
-       int *first_device_num,  /* PCI dev num of the first slot in this PCIE   */
-       int *physical_slot_num, /* phy slot num of the first slot in this PCIE  */
-       u8 *ctrlcap)
-{
-       struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
-       u32 slot_cap;
-       int rc = 0;
-       
-       DBG_ENTER_ROUTINE 
-
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
-
-       *first_device_num = 0;
-       *num_ctlr_slots = 1; 
-
-       rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
-
-       if (rc) {
-               err("%s : hp_register_read_dword SLOT_CAP failed\n", __FUNCTION__);
-               return -1;
-       }
-       
-       *physical_slot_num = slot_cap >> 19;
-       dbg("%s: PSN %d \n", __FUNCTION__, *physical_slot_num);
-       
-       *ctrlcap = slot_cap & 0x0000007f;
-
-       DBG_LEAVE_ROUTINE 
-       return 0;
-}
-
 static void hpc_release_ctlr(struct controller *ctrl)
 {
-       struct php_ctlr_state_s *php_ctlr = ctrl->hpc_ctlr_handle;
-       struct php_ctlr_state_s *p, *p_prev;
-
        DBG_ENTER_ROUTINE 
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return ;
-       }
-
-       if (pciehp_poll_mode) {
-           del_timer(&php_ctlr->int_poll_timer);
-       } else {        
-               if (php_ctlr->irq) {
-                       free_irq(php_ctlr->irq, ctrl);
-                       php_ctlr->irq = 0;
-               }
-       }
-       if (php_ctlr->pci_dev) 
-               php_ctlr->pci_dev = NULL;
-
-       spin_lock(&list_lock);
-       p = php_ctlr_list_head;
-       p_prev = NULL;
-       while (p) {
-               if (p == php_ctlr) {
-                       if (p_prev)
-                               p_prev->pnext = p->pnext;
-                       else
-                               php_ctlr_list_head = p->pnext;
-                       break;
-               } else {
-                       p_prev = p;
-                       p = p->pnext;
-               }
-       }
-       spin_unlock(&list_lock);
-
-       kfree(php_ctlr);
+       if (pciehp_poll_mode)
+               del_timer(&ctrl->poll_timer);
+       else
+               free_irq(ctrl->pci_dev->irq, ctrl);
 
        DBG_LEAVE_ROUTINE
-                         
 }
 
 static int hpc_power_on_slot(struct slot * slot)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        u16 slot_cmd;
        u16 slot_ctrl, slot_status;
-
        int retval = 0;
 
        DBG_ENTER_ROUTINE 
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
-
        dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
-       if (slot->hp_slot >= php_ctlr->num_slots) {
-               err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-               return -1;
-       }
 
        /* Clear sticky power-fault bit from previous power failures */
-       hp_register_read_word(php_ctlr->pci_dev,
-                       SLOT_STATUS(slot->ctrl->cap_base), slot_status);
+       retval = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
+       if (retval) {
+               err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
+               return retval;
+       }
        slot_status &= PWR_FAULT_DETECTED;
-       if (slot_status)
-               hp_register_write_word(php_ctlr->pci_dev,
-                       SLOT_STATUS(slot->ctrl->cap_base), slot_status);
-
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
+       if (slot_status) {
+               retval = pciehp_writew(ctrl, SLOTSTATUS, slot_status);
+               if (retval) {
+                       err("%s: Cannot write to SLOTSTATUS register\n",
+                           __FUNCTION__);
+                       return retval;
+               }
+       }
 
+       retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
        if (retval) {
-               err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
                return retval;
        }
 
@@ -798,7 +708,8 @@ static int hpc_power_on_slot(struct slot * slot)
                err("%s: Write %x command failed!\n", __FUNCTION__, slot_cmd);
                return -1;
        }
-       dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+       dbg("%s: SLOTCTRL %x write cmd %x\n",
+           __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 
        DBG_LEAVE_ROUTINE
 
@@ -807,29 +718,18 @@ static int hpc_power_on_slot(struct slot * slot)
 
 static int hpc_power_off_slot(struct slot * slot)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        u16 slot_cmd;
        u16 slot_ctrl;
-
        int retval = 0;
 
        DBG_ENTER_ROUTINE 
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
-
        dbg("%s: slot->hp_slot %x\n", __FUNCTION__, slot->hp_slot);
-       slot->hp_slot = 0;
-       if (slot->hp_slot >= php_ctlr->num_slots) {
-               err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-               return -1;
-       }
-       retval = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(slot->ctrl->cap_base), slot_ctrl);
 
+       retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
        if (retval) {
-               err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
                return retval;
        }
 
@@ -854,47 +754,25 @@ static int hpc_power_off_slot(struct slot * slot)
                err("%s: Write command failed!\n", __FUNCTION__);
                return -1;
        }
-       dbg("%s: SLOT_CTRL %x write cmd %x\n",__FUNCTION__, SLOT_CTRL(slot->ctrl->cap_base), slot_cmd);
+       dbg("%s: SLOTCTRL %x write cmd %x\n",
+           __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_cmd);
 
        DBG_LEAVE_ROUTINE
 
        return retval;
 }
 
-static irqreturn_t pcie_isr(int IRQ, void *dev_id)
+static irqreturn_t pcie_isr(int irq, void *dev_id)
 {
-       struct controller *ctrl = NULL;
-       struct php_ctlr_state_s *php_ctlr;
-       u8 schedule_flag = 0;
+       struct controller *ctrl = (struct controller *)dev_id;
        u16 slot_status, intr_detect, intr_loc;
        u16 temp_word;
        int hp_slot = 0;        /* only 1 slot per PCI Express port */
        int rc = 0;
 
-       if (!dev_id)
-               return IRQ_NONE;
-
-       if (!pciehp_poll_mode) { 
-               ctrl = dev_id;
-               php_ctlr = ctrl->hpc_ctlr_handle;
-       } else {
-               php_ctlr = dev_id;
-               ctrl = (struct controller *)php_ctlr->callback_instance_id;
-       }
-
-       if (!ctrl) {
-               dbg("%s: dev_id %p ctlr == NULL\n", __FUNCTION__, (void*) dev_id);
-               return IRQ_NONE;
-       }
-       
-       if (!php_ctlr) {
-               dbg("%s: php_ctlr == NULL\n", __FUNCTION__);
-               return IRQ_NONE;
-       }
-
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+       rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
        if (rc) {
-               err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
                return IRQ_NONE;
        }
 
@@ -910,33 +788,38 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
        dbg("%s: intr_loc %x\n", __FUNCTION__, intr_loc);
        /* Mask Hot-plug Interrupt Enable */
        if (!pciehp_poll_mode) {
-               rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+               rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
                if (rc) {
-                       err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+                       err("%s: Cannot read SLOT_CTRL register\n",
+                           __FUNCTION__);
                        return IRQ_NONE;
                }
 
-               dbg("%s: hp_register_read_word SLOT_CTRL with value %x\n", __FUNCTION__, temp_word);
+               dbg("%s: pciehp_readw(SLOTCTRL) with value %x\n",
+                   __FUNCTION__, temp_word);
                temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
-
-               rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+               rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
                if (rc) {
-                       err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+                       err("%s: Cannot write to SLOTCTRL register\n",
+                           __FUNCTION__);
                        return IRQ_NONE;
                }
-               
-               rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+
+               rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
                if (rc) {
-                       err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+                       err("%s: Cannot read SLOT_STATUS register\n",
+                           __FUNCTION__);
                        return IRQ_NONE;
                }
-               dbg("%s: hp_register_read_word SLOT_STATUS with value %x\n", __FUNCTION__, slot_status); 
+               dbg("%s: pciehp_readw(SLOTSTATUS) with value %x\n",
+                   __FUNCTION__, slot_status);
                
                /* Clear command complete interrupt caused by this write */
                temp_word = 0x1f;
-               rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+               rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
                if (rc) {
-                       err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+                       err("%s: Cannot write to SLOTSTATUS register\n",
+                           __FUNCTION__);
                        return IRQ_NONE;
                }
        }
@@ -945,60 +828,65 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
                /* 
                 * Command Complete Interrupt Pending 
                 */
+               ctrl->cmd_busy = 0;
                wake_up_interruptible(&ctrl->queue);
        }
 
-       if ((php_ctlr->switch_change_callback) && (intr_loc & MRL_SENS_CHANGED))
-               schedule_flag += php_ctlr->switch_change_callback(
-                       hp_slot, php_ctlr->callback_instance_id);
-       if ((php_ctlr->attention_button_callback) && (intr_loc & ATTN_BUTTN_PRESSED))
-               schedule_flag += php_ctlr->attention_button_callback(
-                       hp_slot, php_ctlr->callback_instance_id);
-       if ((php_ctlr->presence_change_callback) && (intr_loc & PRSN_DETECT_CHANGED))
-               schedule_flag += php_ctlr->presence_change_callback(
-                       hp_slot , php_ctlr->callback_instance_id);
-       if ((php_ctlr->power_fault_callback) && (intr_loc & PWR_FAULT_DETECTED))
-               schedule_flag += php_ctlr->power_fault_callback(
-                       hp_slot, php_ctlr->callback_instance_id);
+       if (intr_loc & MRL_SENS_CHANGED)
+               pciehp_handle_switch_change(hp_slot, ctrl);
+
+       if (intr_loc & ATTN_BUTTN_PRESSED)
+               pciehp_handle_attention_button(hp_slot, ctrl);
+
+       if (intr_loc & PRSN_DETECT_CHANGED)
+               pciehp_handle_presence_change(hp_slot, ctrl);
+
+       if (intr_loc & PWR_FAULT_DETECTED)
+               pciehp_handle_power_fault(hp_slot, ctrl);
 
        /* Clear all events after serving them */
        temp_word = 0x1F;
-       rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+       rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
        if (rc) {
-               err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+               err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
                return IRQ_NONE;
        }
        /* Unmask Hot-plug Interrupt Enable */
        if (!pciehp_poll_mode) {
-               rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+               rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
                if (rc) {
-                       err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+                       err("%s: Cannot read SLOTCTRL register\n",
+                           __FUNCTION__);
                        return IRQ_NONE;
                }
 
                dbg("%s: Unmask Hot-plug Interrupt Enable\n", __FUNCTION__);
                temp_word = (temp_word & ~HP_INTR_ENABLE) | HP_INTR_ENABLE;
 
-               rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), temp_word);
+               rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
                if (rc) {
-                       err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+                       err("%s: Cannot write to SLOTCTRL register\n",
+                           __FUNCTION__);
                        return IRQ_NONE;
                }
-       
-               rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+
+               rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
                if (rc) {
-                       err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+                       err("%s: Cannot read SLOT_STATUS register\n",
+                           __FUNCTION__);
                        return IRQ_NONE;
                }
                
                /* Clear command complete interrupt caused by this write */
                temp_word = 0x1F;
-               rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+               rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
                if (rc) {
-                       err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+                       err("%s: Cannot write to SLOTSTATUS failed\n",
+                           __FUNCTION__);
                        return IRQ_NONE;
                }
-               dbg("%s: hp_register_write_word SLOT_STATUS with value %x\n", __FUNCTION__, temp_word); 
+               dbg("%s: pciehp_writew(SLOTSTATUS) with value %x\n",
+                   __FUNCTION__, temp_word);
        }
        
        return IRQ_HANDLED;
@@ -1006,27 +894,16 @@ static irqreturn_t pcie_isr(int IRQ, void *dev_id)
 
 static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        enum pcie_link_speed lnk_speed;
        u32     lnk_cap;
        int retval = 0;
 
        DBG_ENTER_ROUTINE 
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
-
-       if (slot->hp_slot >= php_ctlr->num_slots) {
-               err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-               return -1;
-       }
-
-       retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
-
+       retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
        if (retval) {
-               err("%s : hp_register_read_dword  LNK_CAP failed\n", __FUNCTION__);
+               err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
                return retval;
        }
 
@@ -1047,27 +924,16 @@ static int hpc_get_max_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
 
 static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        enum pcie_link_width lnk_wdth;
        u32     lnk_cap;
        int retval = 0;
 
        DBG_ENTER_ROUTINE 
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
-
-       if (slot->hp_slot >= php_ctlr->num_slots) {
-               err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-               return -1;
-       }
-
-       retval = hp_register_read_dword(php_ctlr->pci_dev, LNK_CAP(slot->ctrl->cap_base), lnk_cap);
-
+       retval = pciehp_readl(ctrl, LNKCAP, &lnk_cap);
        if (retval) {
-               err("%s : hp_register_read_dword  LNK_CAP failed\n", __FUNCTION__);
+               err("%s: Cannot read LNKCAP register\n", __FUNCTION__);
                return retval;
        }
 
@@ -1109,27 +975,16 @@ static int hpc_get_max_lnk_width (struct slot *slot, enum pcie_link_width *value
 
 static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        enum pcie_link_speed lnk_speed = PCI_SPEED_UNKNOWN;
        int retval = 0;
        u16 lnk_status;
 
        DBG_ENTER_ROUTINE 
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
-
-       if (slot->hp_slot >= php_ctlr->num_slots) {
-               err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-               return -1;
-       }
-
-       retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
-
+       retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
        if (retval) {
-               err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+               err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
                return retval;
        }
 
@@ -1150,27 +1005,16 @@ static int hpc_get_cur_lnk_speed (struct slot *slot, enum pci_bus_speed *value)
 
 static int hpc_get_cur_lnk_width (struct slot *slot, enum pcie_link_width *value)
 {
-       struct php_ctlr_state_s *php_ctlr = slot->ctrl->hpc_ctlr_handle;
+       struct controller *ctrl = slot->ctrl;
        enum pcie_link_width lnk_wdth = PCIE_LNK_WIDTH_UNKNOWN;
        int retval = 0;
        u16 lnk_status;
 
        DBG_ENTER_ROUTINE 
 
-       if (!php_ctlr) {
-               err("%s: Invalid HPC controller handle!\n", __FUNCTION__);
-               return -1;
-       }
-
-       if (slot->hp_slot >= php_ctlr->num_slots) {
-               err("%s: Invalid HPC slot number!\n", __FUNCTION__);
-               return -1;
-       }
-
-       retval = hp_register_read_word(php_ctlr->pci_dev, LNK_STATUS(slot->ctrl->cap_base), lnk_status);
-
+       retval = pciehp_readw(ctrl, LNKSTATUS, &lnk_status);
        if (retval) {
-               err("%s : hp_register_read_word LNK_STATUS failed\n", __FUNCTION__);
+               err("%s: Cannot read LNKSTATUS register\n", __FUNCTION__);
                return retval;
        }
        
@@ -1218,6 +1062,8 @@ static struct hpc_ops pciehp_hpc_ops = {
        .get_attention_status           = hpc_get_attention_status,
        .get_latch_status               = hpc_get_latch_status,
        .get_adapter_status             = hpc_get_adapter_status,
+       .get_emi_status                 = hpc_get_emi_status,
+       .toggle_emi                     = hpc_toggle_emi,
 
        .get_max_bus_speed              = hpc_get_max_lnk_speed,
        .get_cur_bus_speed              = hpc_get_cur_lnk_speed,
@@ -1305,38 +1151,24 @@ int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
 
 int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 {
-       struct php_ctlr_state_s *php_ctlr, *p;
-       void *instance_id = ctrl;
        int rc;
        static int first = 1;
        u16 temp_word;
        u16 cap_reg;
        u16 intr_enable = 0;
        u32 slot_cap;
-       int cap_base, saved_cap_base;
+       int cap_base;
        u16 slot_status, slot_ctrl;
        struct pci_dev *pdev;
 
        DBG_ENTER_ROUTINE
        
-       spin_lock_init(&list_lock);     
-       php_ctlr = kmalloc(sizeof(struct php_ctlr_state_s), GFP_KERNEL);
-
-       if (!php_ctlr) {        /* allocate controller state data */
-               err("%s: HPC controller memory allocation error!\n", __FUNCTION__);
-               goto abort;
-       }
-
-       memset(php_ctlr, 0, sizeof(struct php_ctlr_state_s));
-       
        pdev = dev->port;
-       php_ctlr->pci_dev = pdev;       /* save pci_dev in context */
+       ctrl->pci_dev = pdev;   /* save pci_dev in context */
 
        dbg("%s: hotplug controller vendor id 0x%x device id 0x%x\n",
                        __FUNCTION__, pdev->vendor, pdev->device);
 
-       saved_cap_base = pcie_cap_base;
-
        if ((cap_base = pci_find_capability(pdev, PCI_CAP_ID_EXP)) == 0) {
                dbg("%s: Can't find PCI_CAP_ID_EXP (0x10)\n", __FUNCTION__);
                goto abort_free_ctlr;
@@ -1344,14 +1176,15 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 
        ctrl->cap_base = cap_base;
 
-       dbg("%s: pcie_cap_base %x\n", __FUNCTION__, pcie_cap_base);
+       dbg("%s: pcie_cap_base %x\n", __FUNCTION__, cap_base);
 
-       rc = hp_register_read_word(pdev, CAP_REG(ctrl->cap_base), cap_reg);
+       rc = pciehp_readw(ctrl, CAPREG, &cap_reg);
        if (rc) {
-               err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+               err("%s: Cannot read CAPREG register\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
-       dbg("%s: CAP_REG offset %x cap_reg %x\n", __FUNCTION__, CAP_REG(ctrl->cap_base), cap_reg);
+       dbg("%s: CAPREG offset %x cap_reg %x\n",
+           __FUNCTION__, ctrl->cap_base + CAPREG, cap_reg);
 
        if (((cap_reg & SLOT_IMPL) == 0) || (((cap_reg & DEV_PORT_TYPE) != 0x0040)
                && ((cap_reg & DEV_PORT_TYPE) != 0x0060))) {
@@ -1359,31 +1192,34 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
                goto abort_free_ctlr;
        }
 
-       rc = hp_register_read_dword(php_ctlr->pci_dev, SLOT_CAP(ctrl->cap_base), slot_cap);
+       rc = pciehp_readl(ctrl, SLOTCAP, &slot_cap);
        if (rc) {
-               err("%s : hp_register_read_word CAP_REG failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTCAP register\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
-       dbg("%s: SLOT_CAP offset %x slot_cap %x\n", __FUNCTION__, SLOT_CAP(ctrl->cap_base), slot_cap);
+       dbg("%s: SLOTCAP offset %x slot_cap %x\n",
+           __FUNCTION__, ctrl->cap_base + SLOTCAP, slot_cap);
 
        if (!(slot_cap & HP_CAP)) {
                dbg("%s : This slot is not hot-plug capable\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
        /* For debugging purpose */
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+       rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
        if (rc) {
-               err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
-       dbg("%s: SLOT_STATUS offset %x slot_status %x\n", __FUNCTION__, SLOT_STATUS(ctrl->cap_base), slot_status);
+       dbg("%s: SLOTSTATUS offset %x slot_status %x\n",
+           __FUNCTION__, ctrl->cap_base + SLOTSTATUS, slot_status);
 
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
+       rc = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
        if (rc) {
-               err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
-       dbg("%s: SLOT_CTRL offset %x slot_ctrl %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), slot_ctrl);
+       dbg("%s: SLOTCTRL offset %x slot_ctrl %x\n",
+           __FUNCTION__, ctrl->cap_base + SLOTCTRL, slot_ctrl);
 
        if (first) {
                spin_lock_init(&hpc_event_lock);
@@ -1405,69 +1241,64 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
        /* setup wait queue */
        init_waitqueue_head(&ctrl->queue);
 
-       /* find the IRQ */
-       php_ctlr->irq = dev->irq;
-
-       /* Save interrupt callback info */
-       php_ctlr->attention_button_callback = pciehp_handle_attention_button;
-       php_ctlr->switch_change_callback = pciehp_handle_switch_change;
-       php_ctlr->presence_change_callback = pciehp_handle_presence_change;
-       php_ctlr->power_fault_callback = pciehp_handle_power_fault;
-       php_ctlr->callback_instance_id = instance_id;
-
        /* return PCI Controller Info */
-       php_ctlr->slot_device_offset = 0;
-       php_ctlr->num_slots = 1;
+       ctrl->slot_device_offset = 0;
+       ctrl->num_slots = 1;
+       ctrl->first_slot = slot_cap >> 19;
+       ctrl->ctrlcap = slot_cap & 0x0000007f;
 
        /* Mask Hot-plug Interrupt Enable */
-       rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+       rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
        if (rc) {
-               err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
 
-       dbg("%s: SLOT_CTRL %x value read %x\n", __FUNCTION__, SLOT_CTRL(ctrl->cap_base), temp_word);
+       dbg("%s: SLOTCTRL %x value read %x\n",
+           __FUNCTION__, ctrl->cap_base + SLOTCTRL, temp_word);
        temp_word = (temp_word & ~HP_INTR_ENABLE & ~CMD_CMPL_INTR_ENABLE) | 0x00;
 
-       rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+       rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
        if (rc) {
-               err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+               err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
 
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+       rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
        if (rc) {
-               err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
 
        temp_word = 0x1F; /* Clear all events */
-       rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+       rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
        if (rc) {
-               err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+               err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
                goto abort_free_ctlr;
        }
 
-       if (pciehp_poll_mode)  {/* Install interrupt polling code */
-               /* Install and start the interrupt polling timer */
-               init_timer(&php_ctlr->int_poll_timer);
-               start_int_poll_timer( php_ctlr, 10 );   /* start with 10 second delay */
+       if (pciehp_poll_mode) {
+               /* Install interrupt polling timer. Start with 10 sec delay */
+               init_timer(&ctrl->poll_timer);
+               start_int_poll_timer(ctrl, 10);
        } else {
                /* Installs the interrupt handler */
-               rc = request_irq(php_ctlr->irq, pcie_isr, IRQF_SHARED, MY_NAME, (void *) ctrl);
-               dbg("%s: request_irq %d for hpc%d (returns %d)\n", __FUNCTION__, php_ctlr->irq, ctlr_seq_num, rc);
+               rc = request_irq(ctrl->pci_dev->irq, pcie_isr, IRQF_SHARED,
+                                MY_NAME, (void *)ctrl);
+               dbg("%s: request_irq %d for hpc%d (returns %d)\n",
+                   __FUNCTION__, ctrl->pci_dev->irq, ctlr_seq_num, rc);
                if (rc) {
-                       err("Can't get irq %d for the hotplug controller\n", php_ctlr->irq);
+                       err("Can't get irq %d for the hotplug controller\n",
+                           ctrl->pci_dev->irq);
                        goto abort_free_ctlr;
                }
        }
-
        dbg("pciehp ctrl b:d:f:irq=0x%x:%x:%x:%x\n", pdev->bus->number,
                PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), dev->irq);
 
-       rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+       rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
        if (rc) {
-               err("%s : hp_register_read_word SLOT_CTRL failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTCTRL register\n", __FUNCTION__);
                goto abort_free_irq;
        }
 
@@ -1491,21 +1322,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
        }
 
        /* Unmask Hot-plug Interrupt Enable for the interrupt notification mechanism case */
-       rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+       rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
        if (rc) {
-               err("%s : hp_register_write_word SLOT_CTRL failed\n", __FUNCTION__);
+               err("%s: Cannot write to SLOTCTRL register\n", __FUNCTION__);
                goto abort_free_irq;
        }
-       rc = hp_register_read_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), slot_status);
+       rc = pciehp_readw(ctrl, SLOTSTATUS, &slot_status);
        if (rc) {
-               err("%s : hp_register_read_word SLOT_STATUS failed\n", __FUNCTION__);
+               err("%s: Cannot read SLOTSTATUS register\n", __FUNCTION__);
                goto abort_disable_intr;
        }
        
        temp_word =  0x1F; /* Clear all events */
-       rc = hp_register_write_word(php_ctlr->pci_dev, SLOT_STATUS(ctrl->cap_base), temp_word);
+       rc = pciehp_writew(ctrl, SLOTSTATUS, temp_word);
        if (rc) {
-               err("%s : hp_register_write_word SLOT_STATUS failed\n", __FUNCTION__);
+               err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
                goto abort_disable_intr;
        }
        
@@ -1518,24 +1349,7 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
                        goto abort_disable_intr;
        }
 
-       /*  Add this HPC instance into the HPC list */
-       spin_lock(&list_lock);
-       if (php_ctlr_list_head == 0) {
-               php_ctlr_list_head = php_ctlr;
-               p = php_ctlr_list_head;
-               p->pnext = NULL;
-       } else {
-               p = php_ctlr_list_head;
-
-               while (p->pnext)
-                       p = p->pnext;
-
-               p->pnext = php_ctlr;
-       }
-       spin_unlock(&list_lock);
-
        ctlr_seq_num++;
-       ctrl->hpc_ctlr_handle = php_ctlr;
        ctrl->hpc_ops = &pciehp_hpc_ops;
 
        DBG_LEAVE_ROUTINE
@@ -1543,24 +1357,21 @@ int pcie_init(struct controller * ctrl, struct pcie_device *dev)
 
        /* We end up here for the many possible ways to fail this API.  */
 abort_disable_intr:
-       rc = hp_register_read_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+       rc = pciehp_readw(ctrl, SLOTCTRL, &temp_word);
        if (!rc) {
                temp_word &= ~(intr_enable | HP_INTR_ENABLE);
-               rc = hp_register_write_word(pdev, SLOT_CTRL(ctrl->cap_base), temp_word);
+               rc = pciehp_writew(ctrl, SLOTCTRL, temp_word);
        }
        if (rc)
                err("%s : disabling interrupts failed\n", __FUNCTION__);
 
 abort_free_irq:
        if (pciehp_poll_mode)
-               del_timer_sync(&php_ctlr->int_poll_timer);
+               del_timer_sync(&ctrl->poll_timer);
        else
-               free_irq(php_ctlr->irq, ctrl);
+               free_irq(ctrl->pci_dev->irq, ctrl);
 
 abort_free_ctlr:
-       pcie_cap_base = saved_cap_base;
-       kfree(php_ctlr);
-abort:
        DBG_LEAVE_ROUTINE
        return -1;
 }
index 5d188c5..78cf071 100644 (file)
@@ -28,6 +28,8 @@
 #include <asm/sn/sn_feature_sets.h>
 #include <asm/sn/sn_sal.h>
 #include <asm/sn/types.h>
+#include <linux/acpi.h>
+#include <asm/sn/acpi.h>
 
 #include "../pci.h"
 
@@ -35,14 +37,17 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
 MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver");
 
-#define PCIIO_ASIC_TYPE_TIOCA          4
+
+/* SAL call error codes. Keep in sync with prom header io/include/pcibr.h */
 #define PCI_SLOT_ALREADY_UP            2       /* slot already up */
 #define PCI_SLOT_ALREADY_DOWN          3       /* slot already down */
 #define PCI_L1_ERR                     7       /* L1 console command error */
 #define PCI_EMPTY_33MHZ                        15      /* empty 33 MHz bus */
+
+
+#define PCIIO_ASIC_TYPE_TIOCA          4
 #define PCI_L1_QSIZE                   128     /* our L1 message buffer size */
 #define SN_MAX_HP_SLOTS                        32      /* max hotplug slots */
-#define SGI_HOTPLUG_PROM_REV           0x0430  /* Min. required PROM version */
 #define SN_SLOT_NAME_SIZE              33      /* size of name string */
 
 /* internal list head */
@@ -227,7 +232,7 @@ static void sn_bus_free_data(struct pci_dev *dev)
 }
 
 static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
-                         int device_num)
+                         int device_num, char **ssdt)
 {
        struct slot *slot = bss_hotplug_slot->private;
        struct pcibus_info *pcibus_info;
@@ -240,7 +245,8 @@ static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
         * Power-on and initialize the slot in the SN
         * PCI infrastructure.
         */
-       rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp);
+       rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp, ssdt);
+
 
        if (rc == PCI_SLOT_ALREADY_UP) {
                dev_dbg(slot->pci_bus->self, "is already active\n");
@@ -335,6 +341,7 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
        int func, num_funcs;
        int new_ppb = 0;
        int rc;
+       char *ssdt = NULL;
        void pcibios_fixup_device_resources(struct pci_dev *);
 
        /* Serialize the Linux PCI infrastructure */
@@ -342,14 +349,29 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
 
        /*
         * Power-on and initialize the slot in the SN
-        * PCI infrastructure.
+        * PCI infrastructure. Also, retrieve the ACPI SSDT
+        * table for the slot (if ACPI capable PROM).
         */
-       rc = sn_slot_enable(bss_hotplug_slot, slot->device_num);
+       rc = sn_slot_enable(bss_hotplug_slot, slot->device_num, &ssdt);
        if (rc) {
                mutex_unlock(&sn_hotplug_mutex);
                return rc;
        }
 
+       if (ssdt)
+               ssdt = __va(ssdt);
+       /* Add the new SSDT for the slot to the ACPI namespace */
+       if (SN_ACPI_BASE_SUPPORT() && ssdt) {
+               acpi_status ret;
+
+               ret = acpi_load_table((struct acpi_table_header *)ssdt);
+               if (ACPI_FAILURE(ret)) {
+                       printk(KERN_ERR "%s: acpi_load_table failed (0x%x)\n",
+                              __FUNCTION__, ret);
+                       /* try to continue on */
+               }
+       }
+
        num_funcs = pci_scan_slot(slot->pci_bus,
                                  PCI_DEVFN(slot->device_num + 1, 0));
        if (!num_funcs) {
@@ -374,7 +396,10 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
                         * pdi_host_pcidev_info).
                         */
                        pcibios_fixup_device_resources(dev);
-                       sn_pci_fixup_slot(dev);
+                       if (SN_ACPI_BASE_SUPPORT())
+                               sn_acpi_slot_fixup(dev);
+                       else
+                               sn_io_slot_fixup(dev);
                        if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
                                unsigned char sec_bus;
                                pci_read_config_byte(dev, PCI_SECONDARY_BUS,
@@ -388,6 +413,63 @@ static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
                }
        }
 
+       /*
+        * Add the slot's devices to the ACPI infrastructure */
+       if (SN_ACPI_BASE_SUPPORT() && ssdt) {
+               unsigned long adr;
+               struct acpi_device *pdevice;
+               struct acpi_device *device;
+               acpi_handle phandle;
+               acpi_handle chandle = NULL;
+               acpi_handle rethandle;
+               acpi_status ret;
+
+               phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+
+               if (acpi_bus_get_device(phandle, &pdevice)) {
+                       dev_dbg(slot->pci_bus->self,
+                               "no parent device, assuming NULL\n");
+                       pdevice = NULL;
+               }
+
+               /*
+                * Walk the rootbus node's immediate children looking for
+                * the slot's device node(s). There can be more than
+                * one for multifunction devices.
+                */
+               for (;;) {
+                       rethandle = NULL;
+                       ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
+                                                  phandle, chandle,
+                                                  &rethandle);
+
+                       if (ret == AE_NOT_FOUND || rethandle == NULL)
+                               break;
+
+                       chandle = rethandle;
+
+                       ret = acpi_evaluate_integer(chandle, METHOD_NAME__ADR,
+                                                   NULL, &adr);
+
+                       if (ACPI_SUCCESS(ret) &&
+                           (adr>>16) == (slot->device_num + 1)) {
+
+                               ret = acpi_bus_add(&device, pdevice, chandle,
+                                                  ACPI_BUS_TYPE_DEVICE);
+                               if (ACPI_FAILURE(ret)) {
+                                       printk(KERN_ERR "%s: acpi_bus_add "
+                                              "failed (0x%x) for slot %d "
+                                              "func %d\n", __FUNCTION__,
+                                              ret, (int)(adr>>16),
+                                              (int)(adr&0xffff));
+                                       /* try to continue on */
+                               } else {
+                                       acpi_bus_start(device);
+                               }
+                       }
+               }
+       }
+
        /* Call the driver for the new device */
        pci_bus_add_devices(slot->pci_bus);
        /* Call the drivers for the new devices subordinate to PPB */
@@ -412,6 +494,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
        struct pci_dev *dev;
        int func;
        int rc;
+       acpi_owner_id ssdt_id = 0;
 
        /* Acquire update access to the bus */
        mutex_lock(&sn_hotplug_mutex);
@@ -422,6 +505,52 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
        if (rc)
                goto leaving;
 
+       /* free the ACPI resources for the slot */
+       if (SN_ACPI_BASE_SUPPORT() &&
+            PCI_CONTROLLER(slot->pci_bus)->acpi_handle) {
+               unsigned long adr;
+               struct acpi_device *device;
+               acpi_handle phandle;
+               acpi_handle chandle = NULL;
+               acpi_handle rethandle;
+               acpi_status ret;
+
+               /* Get the rootbus node pointer */
+               phandle = PCI_CONTROLLER(slot->pci_bus)->acpi_handle;
+
+               /*
+                * Walk the rootbus node's immediate children looking for
+                * the slot's device node(s). There can be more than
+                * one for multifunction devices.
+                */
+               for (;;) {
+                       rethandle = NULL;
+                       ret = acpi_get_next_object(ACPI_TYPE_DEVICE,
+                                                  phandle, chandle,
+                                                  &rethandle);
+
+                       if (ret == AE_NOT_FOUND || rethandle == NULL)
+                               break;
+
+                       chandle = rethandle;
+
+                       ret = acpi_evaluate_integer(chandle,
+                                                   METHOD_NAME__ADR,
+                                                   NULL, &adr);
+                       if (ACPI_SUCCESS(ret) &&
+                           (adr>>16) == (slot->device_num + 1)) {
+                               /* retain the owner id */
+                               acpi_get_id(chandle, &ssdt_id);
+
+                               ret = acpi_bus_get_device(chandle,
+                                                         &device);
+                               if (ACPI_SUCCESS(ret))
+                                       acpi_bus_trim(device, 1);
+                       }
+               }
+
+       }
+
        /* Free the SN resources assigned to the Linux device.*/
        for (func = 0; func < 8;  func++) {
                dev = pci_get_slot(slot->pci_bus,
@@ -434,6 +563,18 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
                }
        }
 
+       /* Remove the SSDT for the slot from the ACPI namespace */
+       if (SN_ACPI_BASE_SUPPORT() && ssdt_id) {
+               acpi_status ret;
+               ret = acpi_unload_table_id(ssdt_id);
+               if (ACPI_FAILURE(ret)) {
+                       printk(KERN_ERR "%s: acpi_unload_table_id "
+                              "failed (0x%x) for id %d\n",
+                              __FUNCTION__, ret, ssdt_id);
+                       /* try to continue on */
+               }
+       }
+
        /* free the collected sysdata pointers */
        sn_bus_free_sysdata();
 
index 3ca6a4f..01d31a1 100644 (file)
@@ -106,7 +106,7 @@ struct controller {
 };
 
 /* Define AMD SHPC ID  */
-#define PCI_DEVICE_ID_AMD_GOLAM_7450   0x7450 
+#define PCI_DEVICE_ID_AMD_GOLAM_7450   0x7450
 #define PCI_DEVICE_ID_AMD_POGO_7458    0x7458
 
 /* AMD PCIX bridge registers */
@@ -221,7 +221,7 @@ enum ctrl_offsets {
 };
 
 static inline struct slot *get_slot(struct hotplug_slot *hotplug_slot)
-{ 
+{
        return hotplug_slot->private;
 }
 
index 590cd3c..5f4bc08 100644 (file)
@@ -401,10 +401,6 @@ static int __init shpcd_init(void)
 {
        int retval = 0;
 
-#ifdef CONFIG_HOTPLUG_PCI_SHPC_POLL_EVENT_MODE
-       shpchp_poll_mode = 1;
-#endif
-
        retval = pci_register_driver(&shpc_driver);
        dbg("%s: pci_register_driver = %d\n", __FUNCTION__, retval);
        info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
index 6bb8473..b746bd2 100644 (file)
@@ -64,7 +64,7 @@ u8 shpchp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
 
        /* Attention Button Change */
        dbg("shpchp:  Attention button interrupt received.\n");
-       
+
        p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
        p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
 
@@ -128,7 +128,7 @@ u8 shpchp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
 
        p_slot = shpchp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
-       /* 
+       /*
         * Save the presence state
         */
        p_slot->hpc_ops->get_adapter_status(p_slot, &(p_slot->presence_save));
@@ -184,12 +184,12 @@ u8 shpchp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
        return 1;
 }
 
-/* The following routines constitute the bulk of the 
+/* The following routines constitute the bulk of the
    hotplug controller logic
  */
 static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
                enum pci_bus_speed speed)
-{ 
+{
        int rc = 0;
 
        dbg("%s: change to speed %d\n", __FUNCTION__, speed);
@@ -204,7 +204,7 @@ static int change_bus_speed(struct controller *ctrl, struct slot *p_slot,
 static int fix_bus_speed(struct controller *ctrl, struct slot *pslot,
                u8 flag, enum pci_bus_speed asp, enum pci_bus_speed bsp,
                enum pci_bus_speed msp)
-{ 
+{
        int rc = 0;
 
        /*
@@ -257,23 +257,23 @@ static int board_added(struct slot *p_slot)
                err("%s: Failed to power on slot\n", __FUNCTION__);
                return -1;
        }
-       
+
        if ((ctrl->pci_dev->vendor == 0x8086) && (ctrl->pci_dev->device == 0x0332)) {
                if (slots_not_empty)
                        return WRONG_BUS_FREQUENCY;
-               
+
                if ((rc = p_slot->hpc_ops->set_bus_speed_mode(p_slot, PCI_SPEED_33MHz))) {
                        err("%s: Issue of set bus speed mode command failed\n", __FUNCTION__);
                        return WRONG_BUS_FREQUENCY;
                }
-               
+
                /* turn on board, blink green LED, turn off Amber LED */
                if ((rc = p_slot->hpc_ops->slot_enable(p_slot))) {
                        err("%s: Issue of Slot Enable command failed\n", __FUNCTION__);
                        return rc;
                }
        }
+
        rc = p_slot->hpc_ops->get_adapter_speed(p_slot, &asp);
        if (rc) {
                err("%s: Can't get adapter speed or bus mode mismatch\n",
@@ -378,7 +378,7 @@ static int remove_board(struct slot *p_slot)
                err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
                return rc;
        }
-       
+
        rc = p_slot->hpc_ops->set_attention_status(p_slot, 0);
        if (rc) {
                err("%s: Issue of Set Attention command failed\n", __FUNCTION__);
index b7bede4..5183a45 100644 (file)
 
 #include "shpchp.h"
 
-#ifdef DEBUG
-#define DBG_K_TRACE_ENTRY      ((unsigned int)0x00000001)      /* On function entry */
-#define DBG_K_TRACE_EXIT       ((unsigned int)0x00000002)      /* On function exit */
-#define DBG_K_INFO             ((unsigned int)0x00000004)      /* Info messages */
-#define DBG_K_ERROR            ((unsigned int)0x00000008)      /* Error messages */
-#define DBG_K_TRACE            (DBG_K_TRACE_ENTRY|DBG_K_TRACE_EXIT)
-#define DBG_K_STANDARD         (DBG_K_INFO|DBG_K_ERROR|DBG_K_TRACE)
-/* Redefine this flagword to set debug level */
-#define DEBUG_LEVEL            DBG_K_STANDARD
-
-#define DEFINE_DBG_BUFFER     char __dbg_str_buf[256];
-
-#define DBG_PRINT( dbg_flags, args... )              \
-       do {                                             \
-         if ( DEBUG_LEVEL & ( dbg_flags ) )             \
-         {                                              \
-           int len;                                     \
-           len = sprintf( __dbg_str_buf, "%s:%d: %s: ", \
-                 __FILE__, __LINE__, __FUNCTION__ );    \
-           sprintf( __dbg_str_buf + len, args );        \
-           printk( KERN_NOTICE "%s\n", __dbg_str_buf ); \
-         }                                              \
-       } while (0)
-
-#define DBG_ENTER_ROUTINE      DBG_PRINT (DBG_K_TRACE_ENTRY, "%s", "[Entry]");
-#define DBG_LEAVE_ROUTINE      DBG_PRINT (DBG_K_TRACE_EXIT, "%s", "[Exit]");
-#else
-#define DEFINE_DBG_BUFFER
-#define DBG_ENTER_ROUTINE
-#define DBG_LEAVE_ROUTINE
-#endif                         /* DEBUG */
-
 /* Slot Available Register I field definition */
 #define SLOT_33MHZ             0x0000001f
 #define SLOT_66MHZ_PCIX                0x00001f00
 #define SLOT_EVENT_LATCH       0x2
 #define SLOT_SERR_INT_MASK     0x3
 
-DEFINE_DBG_BUFFER              /* Debug string buffer for entire HPC defined here */
 static atomic_t shpchp_num_controllers = ATOMIC_INIT(0);
 
 static irqreturn_t shpc_isr(int irq, void *dev_id);
@@ -268,8 +235,6 @@ static void int_poll_timeout(unsigned long data)
 {
        struct controller *ctrl = (struct controller *)data;
 
-       DBG_ENTER_ROUTINE
-
        /* Poll for interrupt events.  regs == NULL => polling */
        shpc_isr(0, ctrl);
 
@@ -278,8 +243,6 @@ static void int_poll_timeout(unsigned long data)
                shpchp_poll_time = 2; /* default polling interval is 2 sec */
 
        start_int_poll_timer(ctrl, shpchp_poll_time);
-
-       DBG_LEAVE_ROUTINE
 }
 
 /*
@@ -353,8 +316,6 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
        int retval = 0;
        u16 temp_word;
 
-       DBG_ENTER_ROUTINE 
-
        mutex_lock(&slot->ctrl->cmd_lock);
 
        if (!shpc_poll_ctrl_busy(ctrl)) {
@@ -368,9 +329,9 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
        ++t_slot;
        temp_word =  (t_slot << 8) | (cmd & 0xFF);
        dbg("%s: t_slot %x cmd %x\n", __FUNCTION__, t_slot, cmd);
-       
+
        /* To make sure the Controller Busy bit is 0 before we send out the
-        * command. 
+        * command.
         */
        shpc_writew(ctrl, CMD, temp_word);
 
@@ -389,20 +350,14 @@ static int shpc_write_cmd(struct slot *slot, u8 t_slot, u8 cmd)
        }
  out:
        mutex_unlock(&slot->ctrl->cmd_lock);
-
-       DBG_LEAVE_ROUTINE 
        return retval;
 }
 
 static int hpc_check_cmd_status(struct controller *ctrl)
 {
-       u16 cmd_status;
        int retval = 0;
+       u16 cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
 
-       DBG_ENTER_ROUTINE 
-
-       cmd_status = shpc_readw(ctrl, CMD_STATUS) & 0x000F;
-       
        switch (cmd_status >> 1) {
        case 0:
                retval = 0;
@@ -423,7 +378,6 @@ static int hpc_check_cmd_status(struct controller *ctrl)
                retval = cmd_status;
        }
 
-       DBG_LEAVE_ROUTINE 
        return retval;
 }
 
@@ -431,13 +385,8 @@ static int hpc_check_cmd_status(struct controller *ctrl)
 static int hpc_get_attention_status(struct slot *slot, u8 *status)
 {
        struct controller *ctrl = slot->ctrl;
-       u32 slot_reg;
-       u8 state;
-       
-       DBG_ENTER_ROUTINE 
-
-       slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
-       state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
+       u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+       u8 state = (slot_reg & ATN_LED_STATE_MASK) >> ATN_LED_STATE_SHIFT;
 
        switch (state) {
        case ATN_LED_STATE_ON:
@@ -454,20 +403,14 @@ static int hpc_get_attention_status(struct slot *slot, u8 *status)
                break;
        }
 
-       DBG_LEAVE_ROUTINE 
        return 0;
 }
 
 static int hpc_get_power_status(struct slot * slot, u8 *status)
 {
        struct controller *ctrl = slot->ctrl;
-       u32 slot_reg;
-       u8 state;
-       
-       DBG_ENTER_ROUTINE 
-
-       slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
-       state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
+       u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+       u8 state = (slot_reg & SLOT_STATE_MASK) >> SLOT_STATE_SHIFT;
 
        switch (state) {
        case SLOT_STATE_PWRONLY:
@@ -484,7 +427,6 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
                break;
        }
 
-       DBG_LEAVE_ROUTINE 
        return 0;
 }
 
@@ -492,30 +434,21 @@ static int hpc_get_power_status(struct slot * slot, u8 *status)
 static int hpc_get_latch_status(struct slot *slot, u8 *status)
 {
        struct controller *ctrl = slot->ctrl;
-       u32 slot_reg;
-
-       DBG_ENTER_ROUTINE 
+       u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
 
-       slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
        *status = !!(slot_reg & MRL_SENSOR);    /* 0 -> close; 1 -> open */
 
-       DBG_LEAVE_ROUTINE 
        return 0;
 }
 
 static int hpc_get_adapter_status(struct slot *slot, u8 *status)
 {
        struct controller *ctrl = slot->ctrl;
-       u32 slot_reg;
-       u8 state;
-
-       DBG_ENTER_ROUTINE 
+       u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+       u8 state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
 
-       slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
-       state = (slot_reg & PRSNT_MASK) >> PRSNT_SHIFT;
        *status = (state != 0x3) ? 1 : 0;
 
-       DBG_LEAVE_ROUTINE 
        return 0;
 }
 
@@ -523,11 +456,8 @@ static int hpc_get_prog_int(struct slot *slot, u8 *prog_int)
 {
        struct controller *ctrl = slot->ctrl;
 
-       DBG_ENTER_ROUTINE 
-
        *prog_int = shpc_readb(ctrl, PROG_INTERFACE);
 
-       DBG_LEAVE_ROUTINE 
        return 0;
 }
 
@@ -539,8 +469,6 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
        u8 m66_cap  = !!(slot_reg & MHZ66_CAP);
        u8 pi, pcix_cap;
 
-       DBG_ENTER_ROUTINE 
-
        if ((retval = hpc_get_prog_int(slot, &pi)))
                return retval;
 
@@ -582,21 +510,15 @@ static int hpc_get_adapter_speed(struct slot *slot, enum pci_bus_speed *value)
        }
 
        dbg("Adapter speed = %d\n", *value);
-       DBG_LEAVE_ROUTINE 
        return retval;
 }
 
 static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
 {
-       struct controller *ctrl = slot->ctrl;
-       u16 sec_bus_status;
-       u8 pi;
        int retval = 0;
-
-       DBG_ENTER_ROUTINE 
-
-       pi = shpc_readb(ctrl, PROG_INTERFACE);
-       sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
+       struct controller *ctrl = slot->ctrl;
+       u16 sec_bus_status = shpc_readw(ctrl, SEC_BUS_CONFIG);
+       u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
 
        if (pi == 2) {
                *mode = (sec_bus_status & 0x0100) >> 8;
@@ -605,21 +527,14 @@ static int hpc_get_mode1_ECC_cap(struct slot *slot, u8 *mode)
        }
 
        dbg("Mode 1 ECC cap = %d\n", *mode);
-       
-       DBG_LEAVE_ROUTINE 
        return retval;
 }
 
 static int hpc_query_power_fault(struct slot * slot)
 {
        struct controller *ctrl = slot->ctrl;
-       u32 slot_reg;
-
-       DBG_ENTER_ROUTINE 
-
-       slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
+       u32 slot_reg = shpc_readl(ctrl, SLOT_REG(slot->hp_slot));
 
-       DBG_LEAVE_ROUTINE
        /* Note: Logic 0 => fault */
        return !(slot_reg & POWER_FAULT);
 }
@@ -629,7 +544,7 @@ static int hpc_set_attention_status(struct slot *slot, u8 value)
        u8 slot_cmd = 0;
 
        switch (value) {
-               case 0 :        
+               case 0 :
                        slot_cmd = SET_ATTN_OFF;        /* OFF */
                        break;
                case 1:
@@ -666,8 +581,6 @@ static void hpc_release_ctlr(struct controller *ctrl)
        int i;
        u32 slot_reg, serr_int;
 
-       DBG_ENTER_ROUTINE 
-
        /*
         * Mask event interrupts and SERRs of all slots
         */
@@ -708,61 +621,43 @@ static void hpc_release_ctlr(struct controller *ctrl)
         */
        if (atomic_dec_and_test(&shpchp_num_controllers))
                destroy_workqueue(shpchp_wq);
-
-       DBG_LEAVE_ROUTINE
 }
 
 static int hpc_power_on_slot(struct slot * slot)
 {
        int retval;
 
-       DBG_ENTER_ROUTINE 
-
        retval = shpc_write_cmd(slot, slot->hp_slot, SET_SLOT_PWR);
-       if (retval) {
+       if (retval)
                err("%s: Write command failed!\n", __FUNCTION__);
-               return retval;
-       }
-
-       DBG_LEAVE_ROUTINE
 
-       return 0;
+       return retval;
 }
 
 static int hpc_slot_enable(struct slot * slot)
 {
        int retval;
 
-       DBG_ENTER_ROUTINE 
-
        /* Slot - Enable, Power Indicator - Blink, Attention Indicator - Off */
        retval = shpc_write_cmd(slot, slot->hp_slot,
                        SET_SLOT_ENABLE | SET_PWR_BLINK | SET_ATTN_OFF);
-       if (retval) {
+       if (retval)
                err("%s: Write command failed!\n", __FUNCTION__);
-               return retval;
-       }
 
-       DBG_LEAVE_ROUTINE
-       return 0;
+       return retval;
 }
 
 static int hpc_slot_disable(struct slot * slot)
 {
        int retval;
 
-       DBG_ENTER_ROUTINE 
-
        /* Slot - Disable, Power Indicator - Off, Attention Indicator - On */
        retval = shpc_write_cmd(slot, slot->hp_slot,
                        SET_SLOT_DISABLE | SET_PWR_OFF | SET_ATTN_ON);
-       if (retval) {
+       if (retval)
                err("%s: Write command failed!\n", __FUNCTION__);
-               return retval;
-       }
 
-       DBG_LEAVE_ROUTINE
-       return 0;
+       return retval;
 }
 
 static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
@@ -771,8 +666,6 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
        struct controller *ctrl = slot->ctrl;
        u8 pi, cmd;
 
-       DBG_ENTER_ROUTINE 
-
        pi = shpc_readb(ctrl, PROG_INTERFACE);
        if ((pi == 1) && (value > PCI_SPEED_133MHz_PCIX))
                return -EINVAL;
@@ -828,7 +721,6 @@ static int hpc_set_bus_speed_mode(struct slot * slot, enum pci_bus_speed value)
        if (retval)
                err("%s: Write command failed!\n", __FUNCTION__);
 
-       DBG_LEAVE_ROUTINE
        return retval;
 }
 
@@ -843,7 +735,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
        if (!intr_loc)
                return IRQ_NONE;
 
-       dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc); 
+       dbg("%s: intr_loc = %x\n",__FUNCTION__, intr_loc);
 
        if(!shpchp_poll_mode) {
                /*
@@ -856,12 +748,12 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
                shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
 
                intr_loc2 = shpc_readl(ctrl, INTR_LOC);
-               dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2); 
+               dbg("%s: intr_loc2 = %x\n",__FUNCTION__, intr_loc2);
        }
 
        if (intr_loc & CMD_INTR_PENDING) {
-               /* 
-                * Command Complete Interrupt Pending 
+               /*
+                * Command Complete Interrupt Pending
                 * RO only - clear by writing 1 to the Command Completion
                 * Detect bit in Controller SERR-INT register
                 */
@@ -875,7 +767,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
        if (!(intr_loc & ~CMD_INTR_PENDING))
                goto out;
 
-       for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) { 
+       for (hp_slot = 0; hp_slot < ctrl->num_slots; hp_slot++) {
                /* To find out which slot has interrupt pending */
                if (!(intr_loc & SLOT_INTR_PENDING(hp_slot)))
                        continue;
@@ -907,7 +799,7 @@ static irqreturn_t shpc_isr(int irq, void *dev_id)
                serr_int &= ~(GLOBAL_INTR_MASK | SERR_INTR_RSVDZ_MASK);
                shpc_writel(ctrl, SERR_INTR_ENABLE, serr_int);
        }
-       
+
        return IRQ_HANDLED;
 }
 
@@ -920,8 +812,6 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
        u32 slot_avail1 = shpc_readl(ctrl, SLOT_AVAIL1);
        u32 slot_avail2 = shpc_readl(ctrl, SLOT_AVAIL2);
 
-       DBG_ENTER_ROUTINE 
-
        if (pi == 2) {
                if (slot_avail2 & SLOT_133MHZ_PCIX_533)
                        bus_speed = PCI_SPEED_133MHz_PCIX_533;
@@ -954,7 +844,7 @@ static int hpc_get_max_bus_speed (struct slot *slot, enum pci_bus_speed *value)
 
        *value = bus_speed;
        dbg("Max bus speed = %d\n", bus_speed);
-       DBG_LEAVE_ROUTINE 
+
        return retval;
 }
 
@@ -967,8 +857,6 @@ static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
        u8 pi = shpc_readb(ctrl, PROG_INTERFACE);
        u8 speed_mode = (pi == 2) ? (sec_bus_reg & 0xF) : (sec_bus_reg & 0x7);
 
-       DBG_ENTER_ROUTINE 
-
        if ((pi == 1) && (speed_mode > 4)) {
                *value = PCI_SPEED_UNKNOWN;
                return -ENODEV;
@@ -1024,7 +912,6 @@ static int hpc_get_cur_bus_speed (struct slot *slot, enum pci_bus_speed *value)
        }
 
        dbg("Current bus speed = %d\n", bus_speed);
-       DBG_LEAVE_ROUTINE 
        return retval;
 }
 
@@ -1032,7 +919,7 @@ static struct hpc_ops shpchp_hpc_ops = {
        .power_on_slot                  = hpc_power_on_slot,
        .slot_enable                    = hpc_slot_enable,
        .slot_disable                   = hpc_slot_disable,
-       .set_bus_speed_mode             = hpc_set_bus_speed_mode,         
+       .set_bus_speed_mode             = hpc_set_bus_speed_mode,
        .set_attention_status   = hpc_set_attention_status,
        .get_power_status               = hpc_get_power_status,
        .get_attention_status   = hpc_get_attention_status,
@@ -1049,7 +936,7 @@ static struct hpc_ops shpchp_hpc_ops = {
        .green_led_on                   = hpc_set_green_led_on,
        .green_led_off                  = hpc_set_green_led_off,
        .green_led_blink                = hpc_set_green_led_blink,
-       
+
        .release_ctlr                   = hpc_release_ctlr,
 };
 
@@ -1061,8 +948,6 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
        u32 tempdword, slot_reg, slot_config;
        u8 i;
 
-       DBG_ENTER_ROUTINE
-
        ctrl->pci_dev = pdev;  /* pci_dev of the P2P bridge */
 
        if ((pdev->vendor == PCI_VENDOR_ID_AMD) || (pdev->device ==
@@ -1108,9 +993,9 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
                ctrl->mmio_size = 0x24 + 0x4 * num_slots;
        }
 
-       info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor, 
+       info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", pdev->vendor, pdev->device, pdev->subsystem_vendor,
                pdev->subsystem_device);
-       
+
        rc = pci_enable_device(pdev);
        if (rc) {
                err("%s: pci_enable_device failed\n", __FUNCTION__);
@@ -1172,7 +1057,7 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
                slot_reg &= ~SLOT_REG_RSVDZ_MASK;
                shpc_writel(ctrl, SLOT_REG(hp_slot), slot_reg);
        }
-       
+
        if (shpchp_poll_mode) {
                /* Install interrupt polling timer. Start with 10 sec delay */
                init_timer(&ctrl->poll_timer);
@@ -1184,7 +1069,7 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
                        info("Can't get msi for the hotplug controller\n");
                        info("Use INTx for the hotplug controller\n");
                }
-               
+
                rc = request_irq(ctrl->pci_dev->irq, shpc_isr, IRQF_SHARED,
                                 MY_NAME, (void *)ctrl);
                dbg("%s: request_irq %d for hpc%d (returns %d)\n",
@@ -1235,13 +1120,11 @@ int shpc_init(struct controller *ctrl, struct pci_dev *pdev)
                dbg("%s: SERR_INTR_ENABLE = %x\n", __FUNCTION__, tempdword);
        }
 
-       DBG_LEAVE_ROUTINE
        return 0;
 
        /* We end up here for the many possible ways to fail this API.  */
 abort_iounmap:
        iounmap(ctrl->creg);
 abort:
-       DBG_LEAVE_ROUTINE
        return rc;
 }
index ed3f7e1..68555c1 100644 (file)
@@ -24,8 +24,6 @@
 #include "pci.h"
 #include "msi.h"
 
-static DEFINE_SPINLOCK(msi_lock);
-static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
 static struct kmem_cache* msi_cachep;
 
 static int pci_msi_enable = 1;
@@ -44,13 +42,13 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
 {
        struct msi_desc *entry;
 
-       entry = msi_desc[irq];
+       entry = get_irq_msi(irq);
        BUG_ON(!entry || !entry->dev);
        switch (entry->msi_attrib.type) {
        case PCI_CAP_ID_MSI:
                if (entry->msi_attrib.maskbit) {
-                       int             pos;
-                       u32             mask_bits;
+                       int pos;
+                       u32 mask_bits;
 
                        pos = (long)entry->mask_base;
                        pci_read_config_dword(entry->dev, pos, &mask_bits);
@@ -74,7 +72,7 @@ static void msi_set_mask_bit(unsigned int irq, int flag)
 
 void read_msi_msg(unsigned int irq, struct msi_msg *msg)
 {
-       struct msi_desc *entry = get_irq_data(irq);
+       struct msi_desc *entry = get_irq_msi(irq);
        switch(entry->msi_attrib.type) {
        case PCI_CAP_ID_MSI:
        {
@@ -113,7 +111,7 @@ void read_msi_msg(unsigned int irq, struct msi_msg *msg)
 
 void write_msi_msg(unsigned int irq, struct msi_msg *msg)
 {
-       struct msi_desc *entry = get_irq_data(irq);
+       struct msi_desc *entry = get_irq_msi(irq);
        switch (entry->msi_attrib.type) {
        case PCI_CAP_ID_MSI:
        {
@@ -162,6 +160,7 @@ void unmask_msi_irq(unsigned int irq)
 }
 
 static int msi_free_irq(struct pci_dev* dev, int irq);
+
 static int msi_init(void)
 {
        static int status = -ENOMEM;
@@ -169,13 +168,6 @@ static int msi_init(void)
        if (!status)
                return status;
 
-       if (pci_msi_quirk) {
-               pci_msi_enable = 0;
-               printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n");
-               status = -EINVAL;
-               return status;
-       }
-
        status = msi_cache_init();
        if (status < 0) {
                pci_msi_enable = 0;
@@ -200,46 +192,6 @@ static struct msi_desc* alloc_msi_entry(void)
        return entry;
 }
 
-static void attach_msi_entry(struct msi_desc *entry, int irq)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&msi_lock, flags);
-       msi_desc[irq] = entry;
-       spin_unlock_irqrestore(&msi_lock, flags);
-}
-
-static int create_msi_irq(void)
-{
-       struct msi_desc *entry;
-       int irq;
-
-       entry = alloc_msi_entry();
-       if (!entry)
-               return -ENOMEM;
-
-       irq = create_irq();
-       if (irq < 0) {
-               kmem_cache_free(msi_cachep, entry);
-               return -EBUSY;
-       }
-
-       set_irq_data(irq, entry);
-
-       return irq;
-}
-
-static void destroy_msi_irq(unsigned int irq)
-{
-       struct msi_desc *entry;
-
-       entry = get_irq_data(irq);
-       set_irq_chip(irq, NULL);
-       set_irq_data(irq, NULL);
-       destroy_irq(irq);
-       kmem_cache_free(msi_cachep, entry);
-}
-
 static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
 {
        u16 control;
@@ -278,36 +230,8 @@ void disable_msi_mode(struct pci_dev *dev, int pos, int type)
        pci_intx(dev, 1);  /* enable intx */
 }
 
-static int msi_lookup_irq(struct pci_dev *dev, int type)
-{
-       int irq;
-       unsigned long flags;
-
-       spin_lock_irqsave(&msi_lock, flags);
-       for (irq = 0; irq < NR_IRQS; irq++) {
-               if (!msi_desc[irq] || msi_desc[irq]->dev != dev ||
-                       msi_desc[irq]->msi_attrib.type != type ||
-                       msi_desc[irq]->msi_attrib.default_irq != dev->irq)
-                       continue;
-               spin_unlock_irqrestore(&msi_lock, flags);
-               /* This pre-assigned MSI irq for this device
-                  already exits. Override dev->irq with this irq */
-               dev->irq = irq;
-               return 0;
-       }
-       spin_unlock_irqrestore(&msi_lock, flags);
-
-       return -EACCES;
-}
-
-void pci_scan_msi_device(struct pci_dev *dev)
-{
-       if (!dev)
-               return;
-}
-
 #ifdef CONFIG_PM
-int pci_save_msi_state(struct pci_dev *dev)
+static int __pci_save_msi_state(struct pci_dev *dev)
 {
        int pos, i = 0;
        u16 control;
@@ -345,7 +269,7 @@ int pci_save_msi_state(struct pci_dev *dev)
        return 0;
 }
 
-void pci_restore_msi_state(struct pci_dev *dev)
+static void __pci_restore_msi_state(struct pci_dev *dev)
 {
        int i = 0, pos;
        u16 control;
@@ -373,14 +297,16 @@ void pci_restore_msi_state(struct pci_dev *dev)
        kfree(save_state);
 }
 
-int pci_save_msix_state(struct pci_dev *dev)
+static int __pci_save_msix_state(struct pci_dev *dev)
 {
        int pos;
-       int temp;
        int irq, head, tail = 0;
        u16 control;
        struct pci_cap_saved_state *save_state;
 
+       if (!dev->msix_enabled)
+               return 0;
+
        pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
        if (pos <= 0 || dev->no_msi)
                return 0;
@@ -398,38 +324,46 @@ int pci_save_msix_state(struct pci_dev *dev)
        *((u16 *)&save_state->data[0]) = control;
 
        /* save the table */
-       temp = dev->irq;
-       if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
-               kfree(save_state);
-               return -EINVAL;
-       }
-
-       irq = head = dev->irq;
+       irq = head = dev->first_msi_irq;
        while (head != tail) {
                struct msi_desc *entry;
 
-               entry = msi_desc[irq];
+               entry = get_irq_msi(irq);
                read_msi_msg(irq, &entry->msg_save);
 
-               tail = msi_desc[irq]->link.tail;
+               tail = entry->link.tail;
                irq = tail;
        }
-       dev->irq = temp;
 
        save_state->cap_nr = PCI_CAP_ID_MSIX;
        pci_add_saved_cap(dev, save_state);
        return 0;
 }
 
-void pci_restore_msix_state(struct pci_dev *dev)
+int pci_save_msi_state(struct pci_dev *dev)
+{
+       int rc;
+
+       rc = __pci_save_msi_state(dev);
+       if (rc)
+               return rc;
+
+       rc = __pci_save_msix_state(dev);
+
+       return rc;
+}
+
+static void __pci_restore_msix_state(struct pci_dev *dev)
 {
        u16 save;
        int pos;
        int irq, head, tail = 0;
        struct msi_desc *entry;
-       int temp;
        struct pci_cap_saved_state *save_state;
 
+       if (!dev->msix_enabled)
+               return;
+
        save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSIX);
        if (!save_state)
                return;
@@ -442,23 +376,25 @@ void pci_restore_msix_state(struct pci_dev *dev)
                return;
 
        /* route the table */
-       temp = dev->irq;
-       if (msi_lookup_irq(dev, PCI_CAP_ID_MSIX))
-               return;
-       irq = head = dev->irq;
+       irq = head = dev->first_msi_irq;
        while (head != tail) {
-               entry = msi_desc[irq];
+               entry = get_irq_msi(irq);
                write_msi_msg(irq, &entry->msg_save);
 
-               tail = msi_desc[irq]->link.tail;
+               tail = entry->link.tail;
                irq = tail;
        }
-       dev->irq = temp;
 
        pci_write_config_word(dev, msi_control_reg(pos), save);
        enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
 }
-#endif
+
+void pci_restore_msi_state(struct pci_dev *dev)
+{
+       __pci_restore_msi_state(dev);
+       __pci_restore_msix_state(dev);
+}
+#endif /* CONFIG_PM */
 
 /**
  * msi_capability_init - configure device's MSI capability structure
@@ -471,7 +407,6 @@ void pci_restore_msix_state(struct pci_dev *dev)
  **/
 static int msi_capability_init(struct pci_dev *dev)
 {
-       int status;
        struct msi_desc *entry;
        int pos, irq;
        u16 control;
@@ -479,13 +414,10 @@ static int msi_capability_init(struct pci_dev *dev)
        pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
        pci_read_config_word(dev, msi_control_reg(pos), &control);
        /* MSI Entry Initialization */
-       irq = create_msi_irq();
-       if (irq < 0)
-               return irq;
+       entry = alloc_msi_entry();
+       if (!entry)
+               return -ENOMEM;
 
-       entry = get_irq_data(irq);
-       entry->link.head = irq;
-       entry->link.tail = irq;
        entry->msi_attrib.type = PCI_CAP_ID_MSI;
        entry->msi_attrib.is_64 = is_64bit_address(control);
        entry->msi_attrib.entry_nr = 0;
@@ -511,13 +443,16 @@ static int msi_capability_init(struct pci_dev *dev)
                        maskbits);
        }
        /* Configure MSI capability structure */
-       status = arch_setup_msi_irq(irq, dev);
-       if (status < 0) {
-               destroy_msi_irq(irq);
-               return status;
+       irq = arch_setup_msi_irq(dev, entry);
+       if (irq < 0) {
+               kmem_cache_free(msi_cachep, entry);
+               return irq;
        }
+       entry->link.head = irq;
+       entry->link.tail = irq;
+       dev->first_msi_irq = irq;
+       set_irq_msi(irq, entry);
 
-       attach_msi_entry(entry, irq);
        /* Set MSI enabled bits  */
        enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
 
@@ -539,7 +474,6 @@ static int msix_capability_init(struct pci_dev *dev,
                                struct msix_entry *entries, int nvec)
 {
        struct msi_desc *head = NULL, *tail = NULL, *entry = NULL;
-       int status;
        int irq, pos, i, j, nr_entries, temp = 0;
        unsigned long phys_addr;
        u32 table_offset;
@@ -562,13 +496,11 @@ static int msix_capability_init(struct pci_dev *dev,
 
        /* MSI-X Table Initialization */
        for (i = 0; i < nvec; i++) {
-               irq = create_msi_irq();
-               if (irq < 0)
+               entry = alloc_msi_entry();
+               if (!entry)
                        break;
 
-               entry = get_irq_data(irq);
                j = entries[i].entry;
-               entries[i].vector = irq;
                entry->msi_attrib.type = PCI_CAP_ID_MSIX;
                entry->msi_attrib.is_64 = 1;
                entry->msi_attrib.entry_nr = j;
@@ -577,6 +509,14 @@ static int msix_capability_init(struct pci_dev *dev,
                entry->msi_attrib.pos = pos;
                entry->dev = dev;
                entry->mask_base = base;
+
+               /* Configure MSI-X capability structure */
+               irq = arch_setup_msi_irq(dev, entry);
+               if (irq < 0) {
+                       kmem_cache_free(msi_cachep, entry);
+                       break;
+               }
+               entries[i].vector = irq;
                if (!head) {
                        entry->link.head = irq;
                        entry->link.tail = irq;
@@ -589,14 +529,8 @@ static int msix_capability_init(struct pci_dev *dev,
                }
                temp = irq;
                tail = entry;
-               /* Configure MSI-X capability structure */
-               status = arch_setup_msi_irq(irq, dev);
-               if (status < 0) {
-                       destroy_msi_irq(irq);
-                       break;
-               }
 
-               attach_msi_entry(entry, irq);
+               set_irq_msi(irq, entry);
        }
        if (i != nvec) {
                int avail = i - 1;
@@ -613,6 +547,7 @@ static int msix_capability_init(struct pci_dev *dev,
                        avail = -EBUSY;
                return avail;
        }
+       dev->first_msi_irq = entries[0].vector;
        /* Set MSI-X enabled bits */
        enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
 
@@ -660,13 +595,11 @@ int pci_msi_supported(struct pci_dev * dev)
  **/
 int pci_enable_msi(struct pci_dev* dev)
 {
-       int pos, temp, status;
+       int pos, status;
 
        if (pci_msi_supported(dev) < 0)
                return -EINVAL;
 
-       temp = dev->irq;
-
        status = msi_init();
        if (status < 0)
                return status;
@@ -675,15 +608,14 @@ int pci_enable_msi(struct pci_dev* dev)
        if (!pos)
                return -EINVAL;
 
-       WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSI));
+       WARN_ON(!!dev->msi_enabled);
 
        /* Check whether driver already requested for MSI-X irqs */
        pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-       if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+       if (pos > 0 && dev->msix_enabled) {
                        printk(KERN_INFO "PCI: %s: Can't enable MSI.  "
-                              "Device already has MSI-X irq assigned\n",
+                              "Device already has MSI-X enabled\n",
                               pci_name(dev));
-                       dev->irq = temp;
                        return -EINVAL;
        }
        status = msi_capability_init(dev);
@@ -695,13 +627,15 @@ void pci_disable_msi(struct pci_dev* dev)
        struct msi_desc *entry;
        int pos, default_irq;
        u16 control;
-       unsigned long flags;
 
        if (!pci_msi_enable)
                return;
        if (!dev)
                return;
 
+       if (!dev->msi_enabled)
+               return;
+
        pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
        if (!pos)
                return;
@@ -710,28 +644,26 @@ void pci_disable_msi(struct pci_dev* dev)
        if (!(control & PCI_MSI_FLAGS_ENABLE))
                return;
 
+
        disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
 
-       spin_lock_irqsave(&msi_lock, flags);
-       entry = msi_desc[dev->irq];
+       entry = get_irq_msi(dev->first_msi_irq);
        if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
-               spin_unlock_irqrestore(&msi_lock, flags);
                return;
        }
-       if (irq_has_action(dev->irq)) {
-               spin_unlock_irqrestore(&msi_lock, flags);
+       if (irq_has_action(dev->first_msi_irq)) {
                printk(KERN_WARNING "PCI: %s: pci_disable_msi() called without "
                       "free_irq() on MSI irq %d\n",
-                      pci_name(dev), dev->irq);
-               BUG_ON(irq_has_action(dev->irq));
+                      pci_name(dev), dev->first_msi_irq);
+               BUG_ON(irq_has_action(dev->first_msi_irq));
        } else {
                default_irq = entry->msi_attrib.default_irq;
-               spin_unlock_irqrestore(&msi_lock, flags);
-               msi_free_irq(dev, dev->irq);
+               msi_free_irq(dev, dev->first_msi_irq);
 
                /* Restore dev->irq to its default pin-assertion irq */
                dev->irq = default_irq;
        }
+       dev->first_msi_irq = 0;
 }
 
 static int msi_free_irq(struct pci_dev* dev, int irq)
@@ -739,27 +671,20 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
        struct msi_desc *entry;
        int head, entry_nr, type;
        void __iomem *base;
-       unsigned long flags;
 
-       arch_teardown_msi_irq(irq);
-
-       spin_lock_irqsave(&msi_lock, flags);
-       entry = msi_desc[irq];
+       entry = get_irq_msi(irq);
        if (!entry || entry->dev != dev) {
-               spin_unlock_irqrestore(&msi_lock, flags);
                return -EINVAL;
        }
        type = entry->msi_attrib.type;
        entry_nr = entry->msi_attrib.entry_nr;
        head = entry->link.head;
        base = entry->mask_base;
-       msi_desc[entry->link.head]->link.tail = entry->link.tail;
-       msi_desc[entry->link.tail]->link.head = entry->link.head;
-       entry->dev = NULL;
-       msi_desc[irq] = NULL;
-       spin_unlock_irqrestore(&msi_lock, flags);
+       get_irq_msi(entry->link.head)->link.tail = entry->link.tail;
+       get_irq_msi(entry->link.tail)->link.head = entry->link.head;
 
-       destroy_msi_irq(irq);
+       arch_teardown_msi_irq(irq);
+       kmem_cache_free(msi_cachep, entry);
 
        if (type == PCI_CAP_ID_MSIX) {
                writel(1, base + entry_nr * PCI_MSIX_ENTRY_SIZE +
@@ -790,7 +715,7 @@ static int msi_free_irq(struct pci_dev* dev, int irq)
 int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
 {
        int status, pos, nr_entries;
-       int i, j, temp;
+       int i, j;
        u16 control;
 
        if (!entries || pci_msi_supported(dev) < 0)
@@ -818,16 +743,14 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
                                return -EINVAL; /* duplicate entry */
                }
        }
-       temp = dev->irq;
-       WARN_ON(!msi_lookup_irq(dev, PCI_CAP_ID_MSIX));
+       WARN_ON(!!dev->msix_enabled);
 
        /* Check whether driver already requested for MSI irq */
        if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 &&
-               !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
+               dev->msi_enabled) {
                printk(KERN_INFO "PCI: %s: Can't enable MSI-X.  "
                       "Device already has an MSI irq assigned\n",
                       pci_name(dev));
-               dev->irq = temp;
                return -EINVAL;
        }
        status = msix_capability_init(dev, entries, nvec);
@@ -836,7 +759,8 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
 
 void pci_disable_msix(struct pci_dev* dev)
 {
-       int pos, temp;
+       int irq, head, tail = 0, warning = 0;
+       int pos;
        u16 control;
 
        if (!pci_msi_enable)
@@ -844,6 +768,9 @@ void pci_disable_msix(struct pci_dev* dev)
        if (!dev)
                return;
 
+       if (!dev->msix_enabled)
+               return;
+
        pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
        if (!pos)
                return;
@@ -854,31 +781,23 @@ void pci_disable_msix(struct pci_dev* dev)
 
        disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
 
-       temp = dev->irq;
-       if (!msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
-               int irq, head, tail = 0, warning = 0;
-               unsigned long flags;
-
-               irq = head = dev->irq;
-               dev->irq = temp;                        /* Restore pin IRQ */
-               while (head != tail) {
-                       spin_lock_irqsave(&msi_lock, flags);
-                       tail = msi_desc[irq]->link.tail;
-                       spin_unlock_irqrestore(&msi_lock, flags);
-                       if (irq_has_action(irq))
-                               warning = 1;
-                       else if (irq != head)   /* Release MSI-X irq */
-                               msi_free_irq(dev, irq);
-                       irq = tail;
-               }
-               msi_free_irq(dev, irq);
-               if (warning) {
-                       printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
-                              "free_irq() on all MSI-X irqs\n",
-                              pci_name(dev));
-                       BUG_ON(warning > 0);
-               }
+       irq = head = dev->first_msi_irq;
+       while (head != tail) {
+               tail = get_irq_msi(irq)->link.tail;
+               if (irq_has_action(irq))
+                       warning = 1;
+               else if (irq != head)   /* Release MSI-X irq */
+                       msi_free_irq(dev, irq);
+               irq = tail;
+       }
+       msi_free_irq(dev, irq);
+       if (warning) {
+               printk(KERN_WARNING "PCI: %s: pci_disable_msix() called without "
+                       "free_irq() on all MSI-X irqs\n",
+                       pci_name(dev));
+               BUG_ON(warning > 0);
        }
+       dev->first_msi_irq = 0;
 }
 
 /**
@@ -892,35 +811,26 @@ void pci_disable_msix(struct pci_dev* dev)
  **/
 void msi_remove_pci_irq_vectors(struct pci_dev* dev)
 {
-       int pos, temp;
-       unsigned long flags;
-
        if (!pci_msi_enable || !dev)
                return;
 
-       temp = dev->irq;                /* Save IOAPIC IRQ */
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
-       if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSI)) {
-               if (irq_has_action(dev->irq)) {
+       if (dev->msi_enabled) {
+               if (irq_has_action(dev->first_msi_irq)) {
                        printk(KERN_WARNING "PCI: %s: msi_remove_pci_irq_vectors() "
                               "called without free_irq() on MSI irq %d\n",
-                              pci_name(dev), dev->irq);
-                       BUG_ON(irq_has_action(dev->irq));
+                              pci_name(dev), dev->first_msi_irq);
+                       BUG_ON(irq_has_action(dev->first_msi_irq));
                } else /* Release MSI irq assigned to this device */
-                       msi_free_irq(dev, dev->irq);
-               dev->irq = temp;                /* Restore IOAPIC IRQ */
+                       msi_free_irq(dev, dev->first_msi_irq);
        }
-       pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
-       if (pos > 0 && !msi_lookup_irq(dev, PCI_CAP_ID_MSIX)) {
+       if (dev->msix_enabled) {
                int irq, head, tail = 0, warning = 0;
                void __iomem *base = NULL;
 
-               irq = head = dev->irq;
+               irq = head = dev->first_msi_irq;
                while (head != tail) {
-                       spin_lock_irqsave(&msi_lock, flags);
-                       tail = msi_desc[irq]->link.tail;
-                       base = msi_desc[irq]->mask_base;
-                       spin_unlock_irqrestore(&msi_lock, flags);
+                       tail = get_irq_msi(irq)->link.tail;
+                       base = get_irq_msi(irq)->mask_base;
                        if (irq_has_action(irq))
                                warning = 1;
                        else if (irq != head) /* Release MSI-X irq */
@@ -935,7 +845,6 @@ void msi_remove_pci_irq_vectors(struct pci_dev* dev)
                               pci_name(dev));
                        BUG_ON(warning > 0);
                }
-               dev->irq = temp;                /* Restore IOAPIC IRQ */
        }
 }
 
index 92d5e8d..4438ae1 100644 (file)
@@ -324,8 +324,7 @@ static int pci_default_resume(struct pci_dev *pci_dev)
        /* restore the PCI config space */
        pci_restore_state(pci_dev);
        /* if the device was enabled before suspend, reenable */
-       if (atomic_read(&pci_dev->enable_cnt))
-               retval = __pci_enable_device(pci_dev);
+       retval = __pci_reenable_device(pci_dev);
        /* if the device was busmaster before the suspend, make it busmaster again */
        if (pci_dev->is_busmaster)
                pci_set_master(pci_dev);
@@ -422,7 +421,8 @@ static struct kobj_type pci_driver_kobj_type = {
  * If no error occurred, the driver remains registered even if 
  * no device was claimed during registration.
  */
-int __pci_register_driver(struct pci_driver *drv, struct module *owner)
+int __pci_register_driver(struct pci_driver *drv, struct module *owner,
+                         const char *mod_name)
 {
        int error;
 
@@ -430,6 +430,7 @@ int __pci_register_driver(struct pci_driver *drv, struct module *owner)
        drv->driver.name = drv->name;
        drv->driver.bus = &pci_bus_type;
        drv->driver.owner = owner;
+       drv->driver.mod_name = mod_name;
        drv->driver.kobj.ktype = &pci_driver_kobj_type;
 
        if (pci_multithread_probe)
index 206c834..84c757b 100644 (file)
@@ -392,6 +392,14 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
        if (state > PCI_D3hot)
                state = PCI_D3hot;
 
+       /*
+        * If the device or the parent bridge can't support PCI PM, ignore
+        * the request if we're doing anything besides putting it into D0
+        * (which would only happen on boot).
+        */
+       if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
+               return 0;
+
        /* Validate current state:
         * Can enter D0 from any state, but if we can only go deeper 
         * to sleep if we're already in a low power state
@@ -403,13 +411,6 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
        } else if (dev->current_state == state)
                return 0;        /* we're already there */
 
-       /*
-        * If the device or the parent bridge can't support PCI PM, ignore
-        * the request if we're doing anything besides putting it into D0
-        * (which would only happen on boot).
-        */
-       if ((state == PCI_D1 || state == PCI_D2) && pci_no_d1d2(dev))
-               return 0;
 
        /* find PCI PM capability in list */
        pm = pci_find_capability(dev, PCI_CAP_ID_PM);
@@ -633,8 +634,6 @@ pci_save_state(struct pci_dev *dev)
                pci_read_config_dword(dev, i * 4,&dev->saved_config_space[i]);
        if ((i = pci_save_msi_state(dev)) != 0)
                return i;
-       if ((i = pci_save_msix_state(dev)) != 0)
-               return i;
        if ((i = pci_save_pcie_state(dev)) != 0)
                return i;
        if ((i = pci_save_pcix_state(dev)) != 0)
@@ -672,22 +671,11 @@ pci_restore_state(struct pci_dev *dev)
        }
        pci_restore_pcix_state(dev);
        pci_restore_msi_state(dev);
-       pci_restore_msix_state(dev);
+
        return 0;
 }
 
-/**
- * pci_enable_device_bars - Initialize some of a device for use
- * @dev: PCI device to be initialized
- * @bars: bitmask of BAR's that must be configured
- *
- *  Initialize device before it's used by a driver. Ask low-level code
- *  to enable selected I/O and memory resources. Wake up the device if it 
- *  was suspended. Beware, this function can fail.
- */
-int
-pci_enable_device_bars(struct pci_dev *dev, int bars)
+static int do_pci_enable_device(struct pci_dev *dev, int bars)
 {
        int err;
 
@@ -697,30 +685,47 @@ pci_enable_device_bars(struct pci_dev *dev, int bars)
        err = pcibios_enable_device(dev, bars);
        if (err < 0)
                return err;
+       pci_fixup_device(pci_fixup_enable, dev);
+
        return 0;
 }
 
 /**
- * __pci_enable_device - Initialize device before it's used by a driver.
+ * __pci_reenable_device - Resume abandoned device
+ * @dev: PCI device to be resumed
+ *
+ *  Note this function is a backend of pci_default_resume and is not supposed
+ *  to be called by normal code, write proper resume handler and use it instead.
+ */
+int
+__pci_reenable_device(struct pci_dev *dev)
+{
+       if (atomic_read(&dev->enable_cnt))
+               return do_pci_enable_device(dev, (1 << PCI_NUM_RESOURCES) - 1);
+       return 0;
+}
+
+/**
+ * pci_enable_device_bars - Initialize some of a device for use
  * @dev: PCI device to be initialized
+ * @bars: bitmask of BAR's that must be configured
  *
  *  Initialize device before it's used by a driver. Ask low-level code
- *  to enable I/O and memory. Wake up the device if it was suspended.
- *  Beware, this function can fail.
- *
- * Note this function is a backend and is not supposed to be called by
- * normal code, use pci_enable_device() instead.
+ *  to enable selected I/O and memory resources. Wake up the device if it
+ *  was suspended. Beware, this function can fail.
  */
 int
-__pci_enable_device(struct pci_dev *dev)
+pci_enable_device_bars(struct pci_dev *dev, int bars)
 {
        int err;
 
-       err = pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
-       if (err)
-               return err;
-       pci_fixup_device(pci_fixup_enable, dev);
-       return 0;
+       if (atomic_add_return(1, &dev->enable_cnt) > 1)
+               return 0;               /* already enabled */
+
+       err = do_pci_enable_device(dev, bars);
+       if (err < 0)
+               atomic_dec(&dev->enable_cnt);
+       return err;
 }
 
 /**
@@ -736,13 +741,7 @@ __pci_enable_device(struct pci_dev *dev)
  */
 int pci_enable_device(struct pci_dev *dev)
 {
-       int result;
-       if (atomic_add_return(1, &dev->enable_cnt) > 1)
-               return 0;               /* already enabled */
-       result = __pci_enable_device(dev);
-       if (result < 0)
-               atomic_dec(&dev->enable_cnt);
-       return result;
+       return pci_enable_device_bars(dev, (1 << PCI_NUM_RESOURCES) - 1);
 }
 
 /**
@@ -921,6 +920,47 @@ err_out:
        return -EBUSY;
 }
 
+/**
+ * pci_release_selected_regions - Release selected PCI I/O and memory resources
+ * @pdev: PCI device whose resources were previously reserved
+ * @bars: Bitmask of BARs to be released
+ *
+ * Release selected PCI I/O and memory resources previously reserved.
+ * Call this function only after all use of the PCI regions has ceased.
+ */
+void pci_release_selected_regions(struct pci_dev *pdev, int bars)
+{
+       int i;
+
+       for (i = 0; i < 6; i++)
+               if (bars & (1 << i))
+                       pci_release_region(pdev, i);
+}
+
+/**
+ * pci_request_selected_regions - Reserve selected PCI I/O and memory resources
+ * @pdev: PCI device whose resources are to be reserved
+ * @bars: Bitmask of BARs to be requested
+ * @res_name: Name to be associated with resource
+ */
+int pci_request_selected_regions(struct pci_dev *pdev, int bars,
+                                const char *res_name)
+{
+       int i;
+
+       for (i = 0; i < 6; i++)
+               if (bars & (1 << i))
+                       if(pci_request_region(pdev, i, res_name))
+                               goto err_out;
+       return 0;
+
+err_out:
+       while(--i >= 0)
+               if (bars & (1 << i))
+                       pci_release_region(pdev, i);
+
+       return -EBUSY;
+}
 
 /**
  *     pci_release_regions - Release reserved PCI I/O and memory resources
@@ -933,10 +973,7 @@ err_out:
 
 void pci_release_regions(struct pci_dev *pdev)
 {
-       int i;
-       
-       for (i = 0; i < 6; i++)
-               pci_release_region(pdev, i);
+       pci_release_selected_regions(pdev, (1 << 6) - 1);
 }
 
 /**
@@ -954,18 +991,7 @@ void pci_release_regions(struct pci_dev *pdev)
  */
 int pci_request_regions(struct pci_dev *pdev, const char *res_name)
 {
-       int i;
-       
-       for (i = 0; i < 6; i++)
-               if(pci_request_region(pdev, i, res_name))
-                       goto err_out;
-       return 0;
-
-err_out:
-       while(--i >= 0)
-               pci_release_region(pdev, i);
-               
-       return -EBUSY;
+       return pci_request_selected_regions(pdev, ((1 << 6) - 1), res_name);
 }
 
 /**
@@ -1148,7 +1174,23 @@ pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask)
        return 0;
 }
 #endif
-     
+
+/**
+ * pci_select_bars - Make BAR mask from the type of resource
+ * @pdev: the PCI device for which BAR mask is made
+ * @flags: resource type mask to be selected
+ *
+ * This helper routine makes bar mask from the type of resource.
+ */
+int pci_select_bars(struct pci_dev *dev, unsigned long flags)
+{
+       int i, bars = 0;
+       for (i = 0; i < PCI_NUM_RESOURCES; i++)
+               if (pci_resource_flags(dev, i) & flags)
+                       bars |= (1 << i);
+       return bars;
+}
+
 static int __devinit pci_init(void)
 {
        struct pci_dev *dev = NULL;
@@ -1181,12 +1223,6 @@ early_param("pci", pci_setup);
 
 device_initcall(pci_init);
 
-#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
-/* FIXME: Some boxes have multiple ISA bridges! */
-struct pci_dev *isa_bridge;
-EXPORT_SYMBOL(isa_bridge);
-#endif
-
 EXPORT_SYMBOL_GPL(pci_restore_bars);
 EXPORT_SYMBOL(pci_enable_device_bars);
 EXPORT_SYMBOL(pci_enable_device);
@@ -1197,6 +1233,8 @@ EXPORT_SYMBOL(pci_release_regions);
 EXPORT_SYMBOL(pci_request_regions);
 EXPORT_SYMBOL(pci_release_region);
 EXPORT_SYMBOL(pci_request_region);
+EXPORT_SYMBOL(pci_release_selected_regions);
+EXPORT_SYMBOL(pci_request_selected_regions);
 EXPORT_SYMBOL(pci_set_master);
 EXPORT_SYMBOL(pci_set_mwi);
 EXPORT_SYMBOL(pci_clear_mwi);
@@ -1205,13 +1243,10 @@ EXPORT_SYMBOL(pci_set_dma_mask);
 EXPORT_SYMBOL(pci_set_consistent_dma_mask);
 EXPORT_SYMBOL(pci_assign_resource);
 EXPORT_SYMBOL(pci_find_parent_resource);
+EXPORT_SYMBOL(pci_select_bars);
 
 EXPORT_SYMBOL(pci_set_power_state);
 EXPORT_SYMBOL(pci_save_state);
 EXPORT_SYMBOL(pci_restore_state);
 EXPORT_SYMBOL(pci_enable_wake);
 
-/* Quirk info */
-
-EXPORT_SYMBOL(isa_dma_bridge_buggy);
-EXPORT_SYMBOL(pci_pci_problems);
index 398852f..a4f2d58 100644 (file)
@@ -1,6 +1,6 @@
 /* Functions internal to the PCI core code */
 
-extern int __must_check __pci_enable_device(struct pci_dev *);
+extern int __must_check __pci_reenable_device(struct pci_dev *);
 extern int pci_uevent(struct device *dev, char **envp, int num_envp,
                      char *buffer, int buffer_size);
 extern int pci_create_sysfs_dev_files(struct pci_dev *pdev);
@@ -43,12 +43,8 @@ extern void pci_remove_legacy_files(struct pci_bus *bus);
 /* Lock for read/write access to pci device and bus lists */
 extern struct rw_semaphore pci_bus_sem;
 
-#ifdef CONFIG_PCI_MSI
-extern int pci_msi_quirk;
-#else
-#define pci_msi_quirk 0
-#endif
 extern unsigned int pci_pm_d3_delay;
+
 #ifdef CONFIG_PCI_MSI
 void disable_msi_mode(struct pci_dev *dev, int pos, int type);
 void pci_no_msi(void);
@@ -56,17 +52,15 @@ void pci_no_msi(void);
 static inline void disable_msi_mode(struct pci_dev *dev, int pos, int type) { }
 static inline void pci_no_msi(void) { }
 #endif
+
 #if defined(CONFIG_PCI_MSI) && defined(CONFIG_PM)
 int pci_save_msi_state(struct pci_dev *dev);
-int pci_save_msix_state(struct pci_dev *dev);
 void pci_restore_msi_state(struct pci_dev *dev);
-void pci_restore_msix_state(struct pci_dev *dev);
 #else
 static inline int pci_save_msi_state(struct pci_dev *dev) { return 0; }
-static inline int pci_save_msix_state(struct pci_dev *dev) { return 0; }
 static inline void pci_restore_msi_state(struct pci_dev *dev) {}
-static inline void pci_restore_msix_state(struct pci_dev *dev) {}
 #endif
+
 static inline int pci_no_d1d2(struct pci_dev *dev)
 {
        unsigned int parent_dstates = 0;
index 0e0401d..2fe1d69 100644 (file)
@@ -144,6 +144,32 @@ static u32 pci_size(u32 base, u32 maxbase, u32 mask)
        return size;
 }
 
+static u64 pci_size64(u64 base, u64 maxbase, u64 mask)
+{
+       u64 size = mask & maxbase;      /* Find the significant bits */
+       if (!size)
+               return 0;
+
+       /* Get the lowest of them to find the decode size, and
+          from that the extent.  */
+       size = (size & ~(size-1)) - 1;
+
+       /* base == maxbase can be valid only if the BAR has
+          already been programmed with all 1s.  */
+       if (base == maxbase && ((base | size) & mask) != mask)
+               return 0;
+
+       return size;
+}
+
+static inline int is_64bit_memory(u32 mask)
+{
+       if ((mask & (PCI_BASE_ADDRESS_SPACE|PCI_BASE_ADDRESS_MEM_TYPE_MASK)) ==
+           (PCI_BASE_ADDRESS_SPACE_MEMORY|PCI_BASE_ADDRESS_MEM_TYPE_64))
+               return 1;
+       return 0;
+}
+
 static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
 {
        unsigned int pos, reg, next;
@@ -151,6 +177,10 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
        struct resource *res;
 
        for(pos=0; pos<howmany; pos = next) {
+               u64 l64;
+               u64 sz64;
+               u32 raw_sz;
+
                next = pos+1;
                res = &dev->resource[pos];
                res->name = pci_name(dev);
@@ -163,9 +193,16 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
                        continue;
                if (l == 0xffffffff)
                        l = 0;
-               if ((l & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
+               raw_sz = sz;
+               if ((l & PCI_BASE_ADDRESS_SPACE) ==
+                               PCI_BASE_ADDRESS_SPACE_MEMORY) {
                        sz = pci_size(l, sz, (u32)PCI_BASE_ADDRESS_MEM_MASK);
-                       if (!sz)
+                       /*
+                        * For 64bit prefetchable memory sz could be 0, if the
+                        * real size is bigger than 4G, so we need to check
+                        * szhi for that.
+                        */
+                       if (!is_64bit_memory(l) && !sz)
                                continue;
                        res->start = l & PCI_BASE_ADDRESS_MEM_MASK;
                        res->flags |= l & ~PCI_BASE_ADDRESS_MEM_MASK;
@@ -178,30 +215,36 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
                }
                res->end = res->start + (unsigned long) sz;
                res->flags |= pci_calc_resource_flags(l);
-               if ((l & (PCI_BASE_ADDRESS_SPACE | PCI_BASE_ADDRESS_MEM_TYPE_MASK))
-                   == (PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_TYPE_64)) {
+               if (is_64bit_memory(l)) {
                        u32 szhi, lhi;
+
                        pci_read_config_dword(dev, reg+4, &lhi);
                        pci_write_config_dword(dev, reg+4, ~0);
                        pci_read_config_dword(dev, reg+4, &szhi);
                        pci_write_config_dword(dev, reg+4, lhi);
-                       szhi = pci_size(lhi, szhi, 0xffffffff);
+                       sz64 = ((u64)szhi << 32) | raw_sz;
+                       l64 = ((u64)lhi << 32) | l;
+                       sz64 = pci_size64(l64, sz64, PCI_BASE_ADDRESS_MEM_MASK);
                        next++;
 #if BITS_PER_LONG == 64
-                       res->start |= ((unsigned long) lhi) << 32;
-                       res->end = res->start + sz;
-                       if (szhi) {
-                               /* This BAR needs > 4GB?  Wow. */
-                               res->end |= (unsigned long)szhi<<32;
+                       if (!sz64) {
+                               res->start = 0;
+                               res->end = 0;
+                               res->flags = 0;
+                               continue;
                        }
+                       res->start = l64 & PCI_BASE_ADDRESS_MEM_MASK;
+                       res->end = res->start + sz64;
 #else
-                       if (szhi) {
-                               printk(KERN_ERR "PCI: Unable to handle 64-bit BAR for device %s\n", pci_name(dev));
+                       if (sz64 > 0x100000000ULL) {
+                               printk(KERN_ERR "PCI: Unable to handle 64-bit "
+                                       "BAR for device %s\n", pci_name(dev));
                                res->start = 0;
                                res->flags = 0;
                        } else if (lhi) {
                                /* 64-bit wide address, treat as disabled */
-                               pci_write_config_dword(dev, reg, l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
+                               pci_write_config_dword(dev, reg,
+                                       l & ~(u32)PCI_BASE_ADDRESS_MEM_MASK);
                                pci_write_config_dword(dev, reg+4, 0);
                                res->start = 0;
                                res->end = sz;
@@ -902,7 +945,6 @@ pci_scan_single_device(struct pci_bus *bus, int devfn)
                return NULL;
 
        pci_device_add(dev, bus);
-       pci_scan_msi_device(dev);
 
        return dev;
 }
index c913ea4..11217bd 100644 (file)
@@ -61,7 +61,8 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82441,      quirk_p
     
     This appears to be BIOS not version dependent. So presumably there is a 
     chipset level fix */
-int isa_dma_bridge_buggy;              /* Exported */
+int isa_dma_bridge_buggy;
+EXPORT_SYMBOL(isa_dma_bridge_buggy);
     
 static void __devinit quirk_isa_dma_hangs(struct pci_dev *dev)
 {
@@ -83,6 +84,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,    PCI_DEVICE_ID_NEC_CBUS_2,       quirk_isa_d
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NEC,     PCI_DEVICE_ID_NEC_CBUS_3,       quirk_isa_dma_hangs );
 
 int pci_pci_problems;
+EXPORT_SYMBOL(pci_pci_problems);
 
 /*
  *     Chipsets where PCI->PCI transfers vanish or hang
@@ -94,6 +96,8 @@ static void __devinit quirk_nopcipci(struct pci_dev *dev)
                pci_pci_problems |= PCIPCI_FAIL;
        }
 }
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5597,          quirk_nopcipci );
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_496,           quirk_nopcipci );
 
 static void __devinit quirk_nopciamd(struct pci_dev *dev)
 {
@@ -105,9 +109,6 @@ static void __devinit quirk_nopciamd(struct pci_dev *dev)
                pci_pci_problems |= PCIAGP_FAIL;
        }
 }
-
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_5597,          quirk_nopcipci );
-DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SI,      PCI_DEVICE_ID_SI_496,           quirk_nopcipci );
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AMD,     PCI_DEVICE_ID_AMD_8151_0,       quirk_nopciamd );
 
 /*
@@ -976,52 +977,51 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
                        case 0x1626: /* L3C notebook */
                                asus_hides_smbus = 1;
                        }
-               if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB)
+               else if (dev->device == PCI_DEVICE_ID_INTEL_82845G_HB)
                        switch(dev->subsystem_device) {
                        case 0x80b1: /* P4GE-V */
                        case 0x80b2: /* P4PE */
                        case 0x8093: /* P4B533-V */
                                asus_hides_smbus = 1;
                        }
-               if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB)
+               else if (dev->device == PCI_DEVICE_ID_INTEL_82850_HB)
                        switch(dev->subsystem_device) {
                        case 0x8030: /* P4T533 */
                                asus_hides_smbus = 1;
                        }
-               if (dev->device == PCI_DEVICE_ID_INTEL_7205_0)
+               else if (dev->device == PCI_DEVICE_ID_INTEL_7205_0)
                        switch (dev->subsystem_device) {
                        case 0x8070: /* P4G8X Deluxe */
                                asus_hides_smbus = 1;
                        }
-               if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH)
+               else if (dev->device == PCI_DEVICE_ID_INTEL_E7501_MCH)
                        switch (dev->subsystem_device) {
                        case 0x80c9: /* PU-DLS */
                                asus_hides_smbus = 1;
                        }
-               if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
+               else if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
                        switch (dev->subsystem_device) {
                        case 0x1751: /* M2N notebook */
                        case 0x1821: /* M5N notebook */
                                asus_hides_smbus = 1;
                        }
-               if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+               else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
                        switch (dev->subsystem_device) {
                        case 0x184b: /* W1N notebook */
                        case 0x186a: /* M6Ne notebook */
                                asus_hides_smbus = 1;
                        }
-               if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
+               else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
                        switch (dev->subsystem_device) {
                        case 0x80f2: /* P4P800-X */
                                asus_hides_smbus = 1;
                        }
-               if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) {
+               else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
                        switch (dev->subsystem_device) {
                        case 0x1882: /* M6V notebook */
                        case 0x1977: /* A6VA notebook */
                                asus_hides_smbus = 1;
                        }
-               }
        } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_HP)) {
                if (dev->device ==  PCI_DEVICE_ID_INTEL_82855PM_HB)
                        switch(dev->subsystem_device) {
@@ -1029,25 +1029,24 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
                        case 0x0890: /* HP Compaq nc6000 */
                                asus_hides_smbus = 1;
                        }
-               if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
+               else if (dev->device == PCI_DEVICE_ID_INTEL_82865_HB)
                        switch (dev->subsystem_device) {
                        case 0x12bc: /* HP D330L */
                        case 0x12bd: /* HP D530 */
                                asus_hides_smbus = 1;
                        }
-               if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB) {
+               else if (dev->device == PCI_DEVICE_ID_INTEL_82915GM_HB)
                        switch (dev->subsystem_device) {
                        case 0x099c: /* HP Compaq nx6110 */
                                asus_hides_smbus = 1;
                        }
-               }
        } else if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_TOSHIBA)) {
                if (dev->device == PCI_DEVICE_ID_INTEL_82855GM_HB)
                        switch(dev->subsystem_device) {
                        case 0x0001: /* Toshiba Satellite A40 */
                                asus_hides_smbus = 1;
                        }
-               if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
+               else if (dev->device == PCI_DEVICE_ID_INTEL_82855PM_HB)
                        switch(dev->subsystem_device) {
                        case 0x0001: /* Toshiba Tecra M2 */
                                asus_hides_smbus = 1;
@@ -1136,6 +1135,14 @@ static void quirk_sis_96x_smbus(struct pci_dev *dev)
                pci_write_config_byte(dev, 0x77, val & ~0x10);
        }
 }
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_961,           quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_962,           quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_963,           quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_LPC,           quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_961,           quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_962,           quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_963,           quirk_sis_96x_smbus );
+DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_LPC,           quirk_sis_96x_smbus );
 
 /*
  * ... This is further complicated by the fact that some SiS96x south
@@ -1145,8 +1152,6 @@ static void quirk_sis_96x_smbus(struct pci_dev *dev)
  *
  * We can also enable the sis96x bit in the discovery register..
  */
-static int __devinitdata sis_96x_compatible = 0;
-
 #define SIS_DETECT_REGISTER 0x40
 
 static void quirk_sis_503(struct pci_dev *dev)
@@ -1162,9 +1167,6 @@ static void quirk_sis_503(struct pci_dev *dev)
                return;
        }
 
-       /* Make people aware that we changed the config.. */
-       printk(KERN_WARNING "Uncovering SIS%x that hid as a SIS503 (compatible=%d)\n", devid, sis_96x_compatible);
-
        /*
         * Ok, it now shows up as a 96x.. run the 96x quirk by
         * hand in case it has already been processed.
@@ -1173,20 +1175,10 @@ static void quirk_sis_503(struct pci_dev *dev)
        dev->device = devid;
        quirk_sis_96x_smbus(dev);
 }
-
-static void __init quirk_sis_96x_compatible(struct pci_dev *dev)
-{
-       sis_96x_compatible = 1;
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_645,           quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_646,           quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_648,           quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_650,           quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_651,           quirk_sis_96x_compatible );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_735,           quirk_sis_96x_compatible );
-
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_503,           quirk_sis_503 );
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_503,           quirk_sis_503 );
+
+
 /*
  * On ASUS A8V and A8V Deluxe boards, the onboard AC97 audio controller
  * and MC97 modem controller are disabled when a second PCI soundcard is
@@ -1217,21 +1209,8 @@ static void asus_hides_ac97_lpc(struct pci_dev *dev)
        }
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
-
-
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_961,           quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_962,           quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_963,           quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_LPC,           quirk_sis_96x_smbus );
-
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_VIA,    PCI_DEVICE_ID_VIA_8237, asus_hides_ac97_lpc );
 
-
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_961,           quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_962,           quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_963,           quirk_sis_96x_smbus );
-DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SI,     PCI_DEVICE_ID_SI_LPC,           quirk_sis_96x_smbus );
-
 #if defined(CONFIG_ATA) || defined(CONFIG_ATA_MODULE)
 
 /*
@@ -1276,7 +1255,6 @@ static void quirk_jmicron_dualfn(struct pci_dev *pdev)
                        break;
        }
 }
-
 DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
 DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_JMICRON, PCI_ANY_ID, quirk_jmicron_dualfn);
 
@@ -1420,6 +1398,7 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,    PCI_ANY_ID,         quirk_intel_ide_co
 
 
 int pcie_mch_quirk;
+EXPORT_SYMBOL(pcie_mch_quirk);
 
 static void __devinit quirk_pcie_mch(struct pci_dev *pdev)
 {
@@ -1481,6 +1460,24 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,     0x2609, quirk_intel_pcie_pm);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   0x260a, quirk_intel_pcie_pm);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   0x260b, quirk_intel_pcie_pm);
 
+/*
+ * Toshiba TC86C001 IDE controller reports the standard 8-byte BAR0 size
+ * but the PIO transfers won't work if BAR0 falls at the odd 8 bytes.
+ * Re-allocate the region if needed...
+ */
+static void __init quirk_tc86c001_ide(struct pci_dev *dev)
+{
+       struct resource *r = &dev->resource[0];
+
+       if (r->start & 0x8) {
+               r->start = 0;
+               r->end = 0xf;
+       }
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_TOSHIBA_2,
+                        PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE,
+                        quirk_tc86c001_ide);
+
 static void __devinit quirk_netmos(struct pci_dev *dev)
 {
        unsigned int num_parallel = (dev->subsystem_device & 0xf0) >> 4;
@@ -1646,6 +1643,7 @@ void pci_fixup_device(enum pci_fixup_pass pass, struct pci_dev *dev)
        }
        pci_do_fixups(dev, start, end);
 }
+EXPORT_SYMBOL(pci_fixup_device);
 
 /* Enable 1k I/O space granularity on the Intel P64H2 */
 static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
@@ -1673,6 +1671,31 @@ static void __devinit quirk_p64h2_1k_io(struct pci_dev *dev)
 }
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,  0x1460,         quirk_p64h2_1k_io);
 
+/* Fix the IOBL_ADR for 1k I/O space granularity on the Intel P64H2
+ * The IOBL_ADR gets re-written to 4k boundaries in pci_setup_bridge()
+ * in drivers/pci/setup-bus.c
+ */
+static void __devinit quirk_p64h2_1k_io_fix_iobl(struct pci_dev *dev)
+{
+       u16 en1k, iobl_adr, iobl_adr_1k;
+       struct resource *res = dev->resource + PCI_BRIDGE_RESOURCES;
+
+       pci_read_config_word(dev, 0x40, &en1k);
+
+       if (en1k & 0x200) {
+               pci_read_config_word(dev, PCI_IO_BASE, &iobl_adr);
+
+               iobl_adr_1k = iobl_adr | (res->start >> 8) | (res->end & 0xfc00);
+
+               if (iobl_adr != iobl_adr_1k) {
+                       printk(KERN_INFO "PCI: Fixing P64H2 IOBL_ADR from 0x%x to 0x%x for 1 KB Granularity\n",
+                               iobl_adr,iobl_adr_1k);
+                       pci_write_config_word(dev, PCI_IO_BASE, iobl_adr_1k);
+               }
+       }
+}
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,   0x1460,         quirk_p64h2_1k_io_fix_iobl);
+
 /* Under some circumstances, AER is not linked with extended capabilities.
  * Force it to be linked by setting the corresponding control bit in the
  * config space.
@@ -1695,9 +1718,6 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_NVIDIA,  PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
                        quirk_nvidia_ck804_pcie_aer_ext_cap);
 
 #ifdef CONFIG_PCI_MSI
-/* To disable MSI globally */
-int pci_msi_quirk;
-
 /* The Serverworks PCI-X chipset does not support MSI. We cannot easily rely
  * on setting PCI_BUS_FLAGS_NO_MSI in its bus flags because there are actually
  * some other busses controlled by the chipset even if Linux is not aware of it.
@@ -1706,8 +1726,8 @@ int pci_msi_quirk;
  */
 static void __init quirk_svw_msi(struct pci_dev *dev)
 {
-       pci_msi_quirk = 1;
-       printk(KERN_WARNING "PCI: MSI quirk detected. pci_msi_quirk set.\n");
+       pci_no_msi();
+       printk(KERN_WARNING "PCI: MSI quirk detected. MSI deactivated.\n");
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_GCNB_LE, quirk_svw_msi);
 
@@ -1788,8 +1808,3 @@ static void __devinit quirk_nvidia_ck804_msi_ht_cap(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_CK804_PCIE,
                        quirk_nvidia_ck804_msi_ht_cap);
 #endif /* CONFIG_PCI_MSI */
-
-EXPORT_SYMBOL(pcie_mch_quirk);
-#ifdef CONFIG_HOTPLUG
-EXPORT_SYMBOL(pci_fixup_device);
-#endif
index b2653c4..ff98ead 100644 (file)
@@ -357,43 +357,6 @@ exit:
        return dev;
 }
 
-/**
- * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id
- * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids
- * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids
- * @from: Previous PCI device found in search, or %NULL for new search.
- *
- * Iterates through the list of known PCI devices in the reverse order of
- * pci_find_device().
- * If a PCI device is found with a matching @vendor and @device, a pointer to
- * its device structure is returned.  Otherwise, %NULL is returned.
- * A new search is initiated by passing %NULL as the @from argument.
- * Otherwise if @from is not %NULL, searches continue from previous device
- * on the global list.
- */
-struct pci_dev *
-pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from)
-{
-       struct list_head *n;
-       struct pci_dev *dev;
-
-       WARN_ON(in_interrupt());
-       down_read(&pci_bus_sem);
-       n = from ? from->global_list.prev : pci_devices.prev;
-
-       while (n && (n != &pci_devices)) {
-               dev = pci_dev_g(n);
-               if ((vendor == PCI_ANY_ID || dev->vendor == vendor) &&
-                   (device == PCI_ANY_ID || dev->device == device))
-                       goto exit;
-               n = n->prev;
-       }
-       dev = NULL;
-exit:
-       up_read(&pci_bus_sem);
-       return dev;
-}
-
 /**
  * pci_get_class - begin or continue searching for a PCI device by class
  * @class: search for a PCI device with this class designation
@@ -469,7 +432,6 @@ EXPORT_SYMBOL(pci_dev_present);
 EXPORT_SYMBOL(pci_find_present);
 
 EXPORT_SYMBOL(pci_find_device);
-EXPORT_SYMBOL(pci_find_device_reverse);
 EXPORT_SYMBOL(pci_find_slot);
 /* For boot time work */
 EXPORT_SYMBOL(pci_find_bus);
index 606a467..ac00424 100644 (file)
@@ -110,7 +110,7 @@ int pcmcia_socket_dev_suspend(struct device *dev, pm_message_t state)
 
        down_read(&pcmcia_socket_list_rwsem);
        list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
-               if (socket->dev.dev != dev)
+               if (socket->dev.parent != dev)
                        continue;
                mutex_lock(&socket->skt_mutex);
                socket_suspend(socket);
@@ -128,7 +128,7 @@ int pcmcia_socket_dev_resume(struct device *dev)
 
        down_read(&pcmcia_socket_list_rwsem);
        list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
-               if (socket->dev.dev != dev)
+               if (socket->dev.parent != dev)
                        continue;
                mutex_lock(&socket->skt_mutex);
                socket_resume(socket);
@@ -143,12 +143,12 @@ EXPORT_SYMBOL(pcmcia_socket_dev_resume);
 
 struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt)
 {
-       struct class_device *cl_dev = class_device_get(&skt->dev);
-       if (!cl_dev)
+       struct device *dev = get_device(&skt->dev);
+       if (!dev)
                return NULL;
-       skt = class_get_devdata(cl_dev);
+       skt = dev_get_drvdata(dev);
        if (!try_module_get(skt->owner)) {
-               class_device_put(&skt->dev);
+               put_device(&skt->dev);
                return NULL;
        }
        return (skt);
@@ -159,14 +159,14 @@ EXPORT_SYMBOL(pcmcia_get_socket);
 void pcmcia_put_socket(struct pcmcia_socket *skt)
 {
        module_put(skt->owner);
-       class_device_put(&skt->dev);
+       put_device(&skt->dev);
 }
 EXPORT_SYMBOL(pcmcia_put_socket);
 
 
-static void pcmcia_release_socket(struct class_device *class_dev)
+static void pcmcia_release_socket(struct device *dev)
 {
-       struct pcmcia_socket *socket = class_get_devdata(class_dev);
+       struct pcmcia_socket *socket = dev_get_drvdata(dev);
 
        complete(&socket->socket_released);
 }
@@ -181,7 +181,7 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
        struct task_struct *tsk;
        int ret;
 
-       if (!socket || !socket->ops || !socket->dev.dev || !socket->resource_ops)
+       if (!socket || !socket->ops || !socket->dev.parent || !socket->resource_ops)
                return -EINVAL;
 
        cs_dbg(socket, 0, "pcmcia_register_socket(0x%p)\n", socket->ops);
@@ -226,9 +226,9 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
 #endif
 
        /* set proper values in socket->dev */
-       socket->dev.class_data = socket;
+       dev_set_drvdata(&socket->dev, socket);
        socket->dev.class = &pcmcia_socket_class;
-       snprintf(socket->dev.class_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
+       snprintf(socket->dev.bus_id, BUS_ID_SIZE, "pcmcia_socket%u", socket->sock);
 
        /* base address = 0, map = 0 */
        socket->cis_mem.flags = 0;
@@ -640,7 +640,7 @@ static int pccardd(void *__skt)
        skt->ops->set_socket(skt, &skt->socket);
 
        /* register with the device core */
-       ret = class_device_register(&skt->dev);
+       ret = device_register(&skt->dev);
        if (ret) {
                printk(KERN_WARNING "PCMCIA: unable to register socket 0x%p\n",
                        skt);
@@ -689,7 +689,7 @@ static int pccardd(void *__skt)
        remove_wait_queue(&skt->thread_wait, &wait);
 
        /* remove from the device core */
-       class_device_unregister(&skt->dev);
+       device_unregister(&skt->dev);
 
        return 0;
 }
@@ -904,7 +904,7 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
 EXPORT_SYMBOL(pcmcia_insert_card);
 
 
-static int pcmcia_socket_uevent(struct class_device *dev, char **envp,
+static int pcmcia_socket_uevent(struct device *dev, char **envp,
                                int num_envp, char *buffer, int buffer_size)
 {
        struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
@@ -930,8 +930,8 @@ static void pcmcia_release_socket_class(struct class *data)
 
 struct class pcmcia_socket_class = {
        .name = "pcmcia_socket",
-       .uevent = pcmcia_socket_uevent,
-       .release = pcmcia_release_socket,
+       .dev_uevent = pcmcia_socket_uevent,
+       .dev_release = pcmcia_release_socket,
        .class_release = pcmcia_release_socket_class,
 };
 EXPORT_SYMBOL(pcmcia_socket_class);
index f573ea0..9fa207e 100644 (file)
@@ -142,7 +142,7 @@ struct pcmcia_callback{
 
 int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
 
-#define cs_socket_name(skt)    ((skt)->dev.class_id)
+#define cs_socket_name(skt)    ((skt)->dev.bus_id)
 
 #ifdef DEBUG
 extern int cs_debug_level(int);
@@ -158,6 +158,6 @@ extern int cs_debug_level(int);
 #endif
 
 #define cs_err(skt, fmt, arg...) \
-       printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.class_id , ## arg)
+       printk(KERN_ERR "cs: %s: " fmt, (skt)->dev.bus_id , ## arg)
 
 #endif /* _LINUX_CS_INTERNAL_H */
index 7355eb4..18e111e 100644 (file)
@@ -572,7 +572,7 @@ struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int f
        p_dev->func   = function;
 
        p_dev->dev.bus = &pcmcia_bus_type;
-       p_dev->dev.parent = s->dev.dev;
+       p_dev->dev.parent = s->dev.parent;
        p_dev->dev.release = pcmcia_release_dev;
        bus_id_len = sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
 
@@ -1328,10 +1328,10 @@ static struct pcmcia_callback pcmcia_bus_callback = {
        .resume = pcmcia_bus_resume,
 };
 
-static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev,
+static int __devinit pcmcia_bus_add_socket(struct device *dev,
                                           struct class_interface *class_intf)
 {
-       struct pcmcia_socket *socket = class_get_devdata(class_dev);
+       struct pcmcia_socket *socket = dev_get_drvdata(dev);
        int ret;
 
        socket = pcmcia_get_socket(socket);
@@ -1364,10 +1364,10 @@ static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev,
        return 0;
 }
 
-static void pcmcia_bus_remove_socket(struct class_device *class_dev,
+static void pcmcia_bus_remove_socket(struct device *dev,
                                     struct class_interface *class_intf)
 {
-       struct pcmcia_socket *socket = class_get_devdata(class_dev);
+       struct pcmcia_socket *socket = dev_get_drvdata(dev);
 
        if (!socket)
                return;
@@ -1389,8 +1389,8 @@ static void pcmcia_bus_remove_socket(struct class_device *class_dev,
 /* the pcmcia_bus_interface is used to handle pcmcia socket devices */
 static struct class_interface pcmcia_bus_interface = {
        .class = &pcmcia_socket_class,
-       .add = &pcmcia_bus_add_socket,
-       .remove = &pcmcia_bus_remove_socket,
+       .add_dev = &pcmcia_bus_add_socket,
+       .remove_dev = &pcmcia_bus_remove_socket,
 };
 
 
index c2ea07a..df21e2d 100644 (file)
@@ -161,7 +161,7 @@ static int __devinit i82092aa_pci_probe(struct pci_dev *dev, const struct pci_de
        pci_set_drvdata(dev, &sockets[i].socket);
 
        for (i = 0; i<socket_count; i++) {
-               sockets[i].socket.dev.dev = &dev->dev;
+               sockets[i].socket.dev.parent = &dev->dev;
                sockets[i].socket.ops = &i82092aa_operations;
                sockets[i].socket.resource_ops = &pccard_nonstatic_ops;
                ret = pcmcia_register_socket(&sockets[i].socket);
index ea74f98..72ff2f6 100644 (file)
@@ -1298,7 +1298,7 @@ static int __init init_i82365(void)
     
     /* register sockets with the pcmcia core */
     for (i = 0; i < sockets; i++) {
-           socket[i].socket.dev.dev = &i82365_device->dev;
+           socket[i].socket.dev.parent = &i82365_device->dev;
            socket[i].socket.ops = &pcic_operations;
            socket[i].socket.resource_ops = &pccard_nonstatic_ops;
            socket[i].socket.owner = THIS_MODULE;
index 327372b..8849414 100644 (file)
@@ -59,7 +59,6 @@ typedef struct user_info_t {
 
 #ifdef DEBUG
 extern int ds_pc_debug;
-#define cs_socket_name(skt)    ((skt)->dev.class_id)
 
 #define ds_dbg(lvl, fmt, arg...) do {          \
        if (ds_pc_debug >= lvl)                         \
index b9201c2..0ce39de 100644 (file)
@@ -48,7 +48,6 @@ static u8 pcmcia_used_irq[NR_IRQS];
 
 #ifdef DEBUG
 extern int ds_pc_debug;
-#define cs_socket_name(skt)    ((skt)->dev.class_id)
 
 #define ds_dbg(skt, lvl, fmt, arg...) do {                     \
        if (ds_pc_debug >= lvl)                                 \
index 360c248..dd0ddf1 100644 (file)
@@ -682,7 +682,7 @@ static int __devinit pd6729_pci_probe(struct pci_dev *dev,
 
                socket[i].socket.ops = &pd6729_operations;
                socket[i].socket.resource_ops = &pccard_nonstatic_ops;
-               socket[i].socket.dev.dev = &dev->dev;
+               socket[i].socket.dev.parent = &dev->dev;
                socket[i].socket.driver_data = &socket[i];
        }
 
index c3176b1..bfcaad6 100644 (file)
@@ -616,7 +616,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
 static struct resource *nonstatic_find_io_region(unsigned long base, int num,
                   unsigned long align, struct pcmcia_socket *s)
 {
-       struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id);
+       struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.bus_id);
        struct socket_data *s_data = s->resource_data;
        struct pcmcia_align_data data;
        unsigned long min = base;
@@ -650,7 +650,7 @@ static struct resource *nonstatic_find_io_region(unsigned long base, int num,
 static struct resource * nonstatic_find_mem_region(u_long base, u_long num,
                u_long align, int low, struct pcmcia_socket *s)
 {
-       struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id);
+       struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.bus_id);
        struct socket_data *s_data = s->resource_data;
        struct pcmcia_align_data data;
        unsigned long min, max;
@@ -897,9 +897,10 @@ EXPORT_SYMBOL(pccard_nonstatic_ops);
 
 /* sysfs interface to the resource database */
 
-static ssize_t show_io_db(struct class_device *class_dev, char *buf)
+static ssize_t show_io_db(struct device *dev,
+                         struct device_attribute *attr, char *buf)
 {
-       struct pcmcia_socket *s = class_get_devdata(class_dev);
+       struct pcmcia_socket *s = dev_get_drvdata(dev);
        struct socket_data *data;
        struct resource_map *p;
        ssize_t ret = 0;
@@ -920,9 +921,11 @@ static ssize_t show_io_db(struct class_device *class_dev, char *buf)
        return (ret);
 }
 
-static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size_t count)
+static ssize_t store_io_db(struct device *dev,
+                          struct device_attribute *attr,
+                          const char *buf, size_t count)
 {
-       struct pcmcia_socket *s = class_get_devdata(class_dev);
+       struct pcmcia_socket *s = dev_get_drvdata(dev);
        unsigned long start_addr, end_addr;
        unsigned int add = ADD_MANAGED_RESOURCE;
        ssize_t ret = 0;
@@ -947,11 +950,12 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size
 
        return ret ? ret : count;
 }
-static CLASS_DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
+static DEVICE_ATTR(available_resources_io, 0600, show_io_db, store_io_db);
 
-static ssize_t show_mem_db(struct class_device *class_dev, char *buf)
+static ssize_t show_mem_db(struct device *dev,
+                          struct device_attribute *attr, char *buf)
 {
-       struct pcmcia_socket *s = class_get_devdata(class_dev);
+       struct pcmcia_socket *s = dev_get_drvdata(dev);
        struct socket_data *data;
        struct resource_map *p;
        ssize_t ret = 0;
@@ -972,9 +976,11 @@ static ssize_t show_mem_db(struct class_device *class_dev, char *buf)
        return (ret);
 }
 
-static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, size_t count)
+static ssize_t store_mem_db(struct device *dev,
+                           struct device_attribute *attr,
+                           const char *buf, size_t count)
 {
-       struct pcmcia_socket *s = class_get_devdata(class_dev);
+       struct pcmcia_socket *s = dev_get_drvdata(dev);
        unsigned long start_addr, end_addr;
        unsigned int add = ADD_MANAGED_RESOURCE;
        ssize_t ret = 0;
@@ -999,25 +1005,25 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz
 
        return ret ? ret : count;
 }
-static CLASS_DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
+static DEVICE_ATTR(available_resources_mem, 0600, show_mem_db, store_mem_db);
 
-static struct class_device_attribute *pccard_rsrc_attributes[] = {
-       &class_device_attr_available_resources_io,
-       &class_device_attr_available_resources_mem,
+static struct device_attribute *pccard_rsrc_attributes[] = {
+       &dev_attr_available_resources_io,
+       &dev_attr_available_resources_mem,
        NULL,
 };
 
-static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev,
+static int __devinit pccard_sysfs_add_rsrc(struct device *dev,
                                           struct class_interface *class_intf)
 {
-       struct pcmcia_socket *s = class_get_devdata(class_dev);
-       struct class_device_attribute **attr;
+       struct pcmcia_socket *s = dev_get_drvdata(dev);
+       struct device_attribute **attr;
        int ret = 0;
        if (s->resource_ops != &pccard_nonstatic_ops)
                return 0;
 
        for (attr = pccard_rsrc_attributes; *attr; attr++) {
-               ret = class_device_create_file(class_dev, *attr);
+               ret = device_create_file(dev, *attr);
                if (ret)
                        break;
        }
@@ -1025,23 +1031,23 @@ static int __devinit pccard_sysfs_add_rsrc(struct class_device *class_dev,
        return ret;
 }
 
-static void __devexit pccard_sysfs_remove_rsrc(struct class_device *class_dev,
+static void __devexit pccard_sysfs_remove_rsrc(struct device *dev,
                                               struct class_interface *class_intf)
 {
-       struct pcmcia_socket *s = class_get_devdata(class_dev);
-       struct class_device_attribute **attr;
+       struct pcmcia_socket *s = dev_get_drvdata(dev);
+       struct device_attribute **attr;
 
        if (s->resource_ops != &pccard_nonstatic_ops)
                return;
 
        for (attr = pccard_rsrc_attributes; *attr; attr++)
-               class_device_remove_file(class_dev, *attr);
+               device_remove_file(dev, *attr);
 }
 
 static struct class_interface pccard_rsrc_interface = {
        .class = &pcmcia_socket_class,
-       .add = &pccard_sysfs_add_rsrc,
-       .remove = __devexit_p(&pccard_sysfs_remove_rsrc),
+       .add_dev = &pccard_sysfs_add_rsrc,
+       .remove_dev = __devexit_p(&pccard_sysfs_remove_rsrc),
 };
 
 static int __init nonstatic_sysfs_init(void)
index e433704..d2a3bea 100644 (file)
@@ -478,10 +478,10 @@ dump_bits(char **p, const char *prefix, unsigned int val, struct bittbl *bits, i
  *
  * Returns: the number of characters added to the buffer
  */
-static ssize_t show_status(struct class_device *class_dev, char *buf)
+static ssize_t show_status(struct device *dev, char *buf)
 {
        struct soc_pcmcia_socket *skt =
-               container_of(class_dev, struct soc_pcmcia_socket, socket.dev);
+               container_of(dev, struct soc_pcmcia_socket, socket.dev);
        char *p = buf;
 
        p+=sprintf(p, "slot     : %d\n", skt->nr);
@@ -747,7 +747,7 @@ int soc_common_drv_pcmcia_probe(struct device *dev, struct pcmcia_low_level *ops
 
                add_timer(&skt->poll_timer);
 
-               class_device_create_file(&skt->socket.dev, &class_device_attr_status);
+               device_create_file(&skt->socket.dev, &device_attr_status);
        }
 
        dev_set_drvdata(dev, sinfo);
index b005602..ea5765c 100644 (file)
@@ -40,7 +40,8 @@
 
 #define to_socket(_dev) container_of(_dev, struct pcmcia_socket, dev)
 
-static ssize_t pccard_show_type(struct class_device *dev, char *buf)
+static ssize_t pccard_show_type(struct device *dev, struct device_attribute *attr,
+                               char *buf)
 {
        struct pcmcia_socket *s = to_socket(dev);
 
@@ -50,9 +51,10 @@ static ssize_t pccard_show_type(struct class_device *dev, char *buf)
                return sprintf(buf, "32-bit\n");
        return sprintf(buf, "16-bit\n");
 }
-static CLASS_DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL);
+static DEVICE_ATTR(card_type, 0444, pccard_show_type, NULL);
 
-static ssize_t pccard_show_voltage(struct class_device *dev, char *buf)
+static ssize_t pccard_show_voltage(struct device *dev, struct device_attribute *attr,
+                                  char *buf)
 {
        struct pcmcia_socket *s = to_socket(dev);
 
@@ -63,28 +65,31 @@ static ssize_t pccard_show_voltage(struct class_device *dev, char *buf)
                               s->socket.Vcc % 10);
        return sprintf(buf, "X.XV\n");
 }
-static CLASS_DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL);
+static DEVICE_ATTR(card_voltage, 0444, pccard_show_voltage, NULL);
 
-static ssize_t pccard_show_vpp(struct class_device *dev, char *buf)
+static ssize_t pccard_show_vpp(struct device *dev, struct device_attribute *attr,
+                              char *buf)
 {
        struct pcmcia_socket *s = to_socket(dev);
        if (!(s->state & SOCKET_PRESENT))
                return -ENODEV;
        return sprintf(buf, "%d.%dV\n", s->socket.Vpp / 10, s->socket.Vpp % 10);
 }
-static CLASS_DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL);
+static DEVICE_ATTR(card_vpp, 0444, pccard_show_vpp, NULL);
 
-static ssize_t pccard_show_vcc(struct class_device *dev, char *buf)
+static ssize_t pccard_show_vcc(struct device *dev, struct device_attribute *attr,
+                              char *buf)
 {
        struct pcmcia_socket *s = to_socket(dev);
        if (!(s->state & SOCKET_PRESENT))
                return -ENODEV;
        return sprintf(buf, "%d.%dV\n", s->socket.Vcc / 10, s->socket.Vcc % 10);
 }
-static CLASS_DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
+static DEVICE_ATTR(card_vcc, 0444, pccard_show_vcc, NULL);
 
 
-static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_insert(struct device *dev, struct device_attribute *attr,
+                                  const char *buf, size_t count)
 {
        ssize_t ret;
        struct pcmcia_socket *s = to_socket(dev);
@@ -96,16 +101,20 @@ static ssize_t pccard_store_insert(struct class_device *dev, const char *buf, si
 
        return ret ? ret : count;
 }
-static CLASS_DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
+static DEVICE_ATTR(card_insert, 0200, NULL, pccard_store_insert);
 
 
-static ssize_t pccard_show_card_pm_state(struct class_device *dev, char *buf)
+static ssize_t pccard_show_card_pm_state(struct device *dev,
+                                        struct device_attribute *attr,
+                                        char *buf)
 {
        struct pcmcia_socket *s = to_socket(dev);
        return sprintf(buf, "%s\n", s->state & SOCKET_SUSPEND ? "off" : "on");
 }
 
-static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_card_pm_state(struct device *dev,
+                                         struct device_attribute *attr,
+                                         const char *buf, size_t count)
 {
        ssize_t ret = -EINVAL;
        struct pcmcia_socket *s = to_socket(dev);
@@ -120,9 +129,11 @@ static ssize_t pccard_store_card_pm_state(struct class_device *dev, const char *
 
        return ret ? -ENODEV : count;
 }
-static CLASS_DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
+static DEVICE_ATTR(card_pm_state, 0644, pccard_show_card_pm_state, pccard_store_card_pm_state);
 
-static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_eject(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t count)
 {
        ssize_t ret;
        struct pcmcia_socket *s = to_socket(dev);
@@ -134,16 +145,20 @@ static ssize_t pccard_store_eject(struct class_device *dev, const char *buf, siz
 
        return ret ? ret : count;
 }
-static CLASS_DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
+static DEVICE_ATTR(card_eject, 0200, NULL, pccard_store_eject);
 
 
-static ssize_t pccard_show_irq_mask(struct class_device *dev, char *buf)
+static ssize_t pccard_show_irq_mask(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buf)
 {
        struct pcmcia_socket *s = to_socket(dev);
        return sprintf(buf, "0x%04x\n", s->irq_mask);
 }
 
-static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_irq_mask(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
 {
        ssize_t ret;
        struct pcmcia_socket *s = to_socket(dev);
@@ -161,16 +176,19 @@ static ssize_t pccard_store_irq_mask(struct class_device *dev, const char *buf,
 
        return ret ? ret : count;
 }
-static CLASS_DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
+static DEVICE_ATTR(card_irq_mask, 0600, pccard_show_irq_mask, pccard_store_irq_mask);
 
 
-static ssize_t pccard_show_resource(struct class_device *dev, char *buf)
+static ssize_t pccard_show_resource(struct device *dev,
+                                   struct device_attribute *attr, char *buf)
 {
        struct pcmcia_socket *s = to_socket(dev);
        return sprintf(buf, "%s\n", s->resource_setup_done ? "yes" : "no");
 }
 
-static ssize_t pccard_store_resource(struct class_device *dev, const char *buf, size_t count)
+static ssize_t pccard_store_resource(struct device *dev,
+                                    struct device_attribute *attr,
+                                    const char *buf, size_t count)
 {
        unsigned long flags;
        struct pcmcia_socket *s = to_socket(dev);
@@ -196,7 +214,7 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf,
 
        return count;
 }
-static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
+static DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
 
 
 static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count)
@@ -279,7 +297,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size
                if (off + count > size)
                        count = size - off;
 
-               s = to_socket(container_of(kobj, struct class_device, kobj));
+               s = to_socket(container_of(kobj, struct device, kobj));
 
                if (!(s->state & SOCKET_PRESENT))
                        return -ENODEV;
@@ -296,7 +314,7 @@ static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size
 
 static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
 {
-       struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj));
+       struct pcmcia_socket *s = to_socket(container_of(kobj, struct device, kobj));
        cisdump_t *cis;
        int error;
 
@@ -335,16 +353,16 @@ static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, siz
 }
 
 
-static struct class_device_attribute *pccard_socket_attributes[] = {
-       &class_device_attr_card_type,
-       &class_device_attr_card_voltage,
-       &class_device_attr_card_vpp,
-       &class_device_attr_card_vcc,
-       &class_device_attr_card_insert,
-       &class_device_attr_card_pm_state,
-       &class_device_attr_card_eject,
-       &class_device_attr_card_irq_mask,
-       &class_device_attr_available_resources_setup_done,
+static struct device_attribute *pccard_socket_attributes[] = {
+       &dev_attr_card_type,
+       &dev_attr_card_voltage,
+       &dev_attr_card_vpp,
+       &dev_attr_card_vcc,
+       &dev_attr_card_insert,
+       &dev_attr_card_pm_state,
+       &dev_attr_card_eject,
+       &dev_attr_card_irq_mask,
+       &dev_attr_available_resources_setup_done,
        NULL,
 };
 
@@ -355,35 +373,35 @@ static struct bin_attribute pccard_cis_attr = {
        .write = pccard_store_cis,
 };
 
-static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev,
+static int __devinit pccard_sysfs_add_socket(struct device *dev,
                                             struct class_interface *class_intf)
 {
-       struct class_device_attribute **attr;
+       struct device_attribute **attr;
        int ret = 0;
 
        for (attr = pccard_socket_attributes; *attr; attr++) {
-               ret = class_device_create_file(class_dev, *attr);
+               ret = device_create_file(dev, *attr);
                if (ret)
                        break;
        }
        if (!ret)
-               ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr);
+               ret = sysfs_create_bin_file(&dev->kobj, &pccard_cis_attr);
 
        return ret;
 }
 
-static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev,
+static void __devexit pccard_sysfs_remove_socket(struct device *dev,
                                                 struct class_interface *class_intf)
 {
-       struct class_device_attribute **attr;
+       struct device_attribute **attr;
 
-       sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr);
+       sysfs_remove_bin_file(&dev->kobj, &pccard_cis_attr);
        for (attr = pccard_socket_attributes; *attr; attr++)
-               class_device_remove_file(class_dev, *attr);
+               device_remove_file(dev, *attr);
 }
 
 struct class_interface pccard_sysfs_interface = {
        .class = &pcmcia_socket_class,
-       .add = &pccard_sysfs_add_socket,
-       .remove = __devexit_p(&pccard_sysfs_remove_socket),
+       .add_dev = &pccard_sysfs_add_socket,
+       .remove_dev = __devexit_p(&pccard_sysfs_remove_socket),
 };
index 2d2f415..c158cf3 100644 (file)
@@ -512,7 +512,7 @@ static int __init init_tcic(void)
     for (i = 0; i < sockets; i++) {
            socket_table[i].socket.ops = &tcic_operations;
            socket_table[i].socket.resource_ops = &pccard_nonstatic_ops;
-           socket_table[i].socket.dev.dev = &tcic_device.dev;
+           socket_table[i].socket.dev.parent = &tcic_device.dev;
            ret = pcmcia_register_socket(&socket_table[i].socket);
            if (ret && i)
                    pcmcia_unregister_socket(&socket_table[0].socket);
index da471bd..a61d768 100644 (file)
@@ -1104,7 +1104,7 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
        /* prepare pcmcia_socket */
        socket->socket.ops = &yenta_socket_operations;
        socket->socket.resource_ops = &pccard_nonstatic_ops;
-       socket->socket.dev.dev = &dev->dev;
+       socket->socket.dev.parent = &dev->dev;
        socket->socket.driver_data = socket;
        socket->socket.owner = THIS_MODULE;
        socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
index b185417..ad27e5e 100644 (file)
@@ -2,8 +2,8 @@
 # Plug and Play ACPI configuration
 #
 config PNPACPI
-       bool "Plug and Play ACPI support (EXPERIMENTAL)"
-       depends on PNP && ACPI && EXPERIMENTAL
+       bool "Plug and Play ACPI support"
+       depends on PNP && ACPI
        default y
        ---help---
          Linux uses the PNPACPI to autodetect built-in
index d42015c..2065e74 100644 (file)
@@ -3,7 +3,8 @@
  *
  * Some code is based on pnpbios_core.c
  * Copyright 2002 Adam Belay <ambx1@neo.rr.com>
- *
+ * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
+ *     Bjorn Helgaas <bjorn.helgaas@hp.com>
  */
 
 #include <linux/pnp.h>
@@ -21,18 +22,21 @@ static const struct pnp_device_id pnp_dev_table[] = {
        {       "",                     0       }
 };
 
-static void reserve_ioport_range(char *pnpid, int start, int end)
+static void reserve_range(char *pnpid, int start, int end, int port)
 {
        struct resource *res;
        char *regionid;
 
        regionid = kmalloc(16, GFP_KERNEL);
-       if ( regionid == NULL )
+       if (regionid == NULL)
                return;
        snprintf(regionid, 16, "pnp %s", pnpid);
-       res = request_region(start,end-start+1,regionid);
-       if ( res == NULL )
-               kfree( regionid );
+       if (port)
+               res = request_region(start,end-start+1,regionid);
+       else
+               res = request_mem_region(start,end-start+1,regionid);
+       if (res == NULL)
+               kfree(regionid);
        else
                res->flags &= ~IORESOURCE_BUSY;
        /*
@@ -41,26 +45,20 @@ static void reserve_ioport_range(char *pnpid, int start, int end)
         * have double reservations.
         */
        printk(KERN_INFO
-               "pnp: %s: ioport range 0x%x-0x%x %s reserved\n",
-               pnpid, start, end,
-               NULL != res ? "has been" : "could not be"
-       );
-
-       return;
+               "pnp: %s: %s range 0x%x-0x%x %s reserved\n",
+               pnpid, port ? "ioport" : "iomem", start, end,
+               NULL != res ? "has been" : "could not be");
 }
 
-static void reserve_resources_of_dev( struct pnp_dev *dev )
+static void reserve_resources_of_dev(struct pnp_dev *dev)
 {
        int i;
 
-       for (i=0;i<PNP_MAX_PORT;i++) {
+       for (i = 0; i < PNP_MAX_PORT; i++) {
                if (!pnp_port_valid(dev, i))
-                       /* end of resources */
                        continue;
                if (pnp_port_start(dev, i) == 0)
-                       /* disabled */
-                       /* Do nothing */
-                       continue;
+                       continue;       /* disabled */
                if (pnp_port_start(dev, i) < 0x100)
                        /*
                         * Below 0x100 is only standard PC hardware
@@ -72,14 +70,18 @@ static void reserve_resources_of_dev( struct pnp_dev *dev )
                         */
                        continue;
                if (pnp_port_end(dev, i) < pnp_port_start(dev, i))
-                       /* invalid endpoint */
-                       /* Do nothing */
+                       continue;       /* invalid */
+
+               reserve_range(dev->dev.bus_id, pnp_port_start(dev, i),
+                       pnp_port_end(dev, i), 1);
+       }
+
+       for (i = 0; i < PNP_MAX_MEM; i++) {
+               if (!pnp_mem_valid(dev, i))
                        continue;
-               reserve_ioport_range(
-                       dev->dev.bus_id,
-                       pnp_port_start(dev, i),
-                       pnp_port_end(dev, i)
-               );
+
+               reserve_range(dev->dev.bus_id, pnp_mem_start(dev, i),
+                       pnp_mem_end(dev, i), 0);
        }
 
        return;
index ae89b9b..165af39 100644 (file)
@@ -103,14 +103,8 @@ config CCW_CONSOLE
        depends on TN3215_CONSOLE || TN3270_CONSOLE
        default y
  
-config SCLP
-       bool "Support for SCLP"
-       help
-         Include support for the SCLP interface to the service element.
-
 config SCLP_TTY
        bool "Support for SCLP line mode terminal"
-       depends on SCLP
        help
          Include support for IBM SCLP line-mode terminals.
 
@@ -123,7 +117,6 @@ config SCLP_CONSOLE
 
 config SCLP_VT220_TTY
        bool "Support for SCLP VT220-compatible terminal"
-       depends on SCLP
        help
          Include support for an IBM SCLP VT220-compatible terminal.
 
@@ -136,7 +129,6 @@ config SCLP_VT220_CONSOLE
 
 config SCLP_CPI
        tristate "Control-Program Identification"
-       depends on SCLP
        help
          This option enables the hardware console interface for system
          identification. This is commonly used for workload management and
index 9803c93..5a88870 100644 (file)
@@ -2,6 +2,8 @@
 # Makefile for the S/390 specific device drivers
 #
 
+CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
+
 obj-y += s390mach.o sysinfo.o s390_rdev.o
 obj-y += cio/ block/ char/ crypto/ net/ scsi/
 
index 492b68b..eb5dc62 100644 (file)
@@ -37,6 +37,7 @@
  */
 debug_info_t *dasd_debug_area;
 struct dasd_discipline *dasd_diag_discipline_pointer;
+void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
 
 MODULE_AUTHOR("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
 MODULE_DESCRIPTION("Linux on S/390 DASD device driver,"
@@ -51,7 +52,6 @@ static int  dasd_alloc_queue(struct dasd_device * device);
 static void dasd_setup_queue(struct dasd_device * device);
 static void dasd_free_queue(struct dasd_device * device);
 static void dasd_flush_request_queue(struct dasd_device *);
-static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
 static int dasd_flush_ccw_queue(struct dasd_device *, int);
 static void dasd_tasklet(struct dasd_device *);
 static void do_kick_device(struct work_struct *);
@@ -483,7 +483,7 @@ unsigned int dasd_profile_level = DASD_PROFILE_OFF;
 /*
  * Add profiling information for cqr before execution.
  */
-static inline void
+static void
 dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
                   struct request *req)
 {
@@ -505,7 +505,7 @@ dasd_profile_start(struct dasd_device *device, struct dasd_ccw_req * cqr,
 /*
  * Add profiling information for cqr after execution.
  */
-static inline void
+static void
 dasd_profile_end(struct dasd_device *device, struct dasd_ccw_req * cqr,
                 struct request *req)
 {
@@ -1022,8 +1022,6 @@ dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
                 irb->scsw.cstat == 0 &&
                 !irb->esw.esw0.erw.cons)
                era = dasd_era_none;
-       else if (!test_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags))
-               era = dasd_era_fatal; /* don't recover this request */
        else if (irb->esw.esw0.erw.cons)
                era = device->discipline->examine_error(cqr, irb);
        else
@@ -1104,7 +1102,7 @@ __dasd_process_erp(struct dasd_device *device, struct dasd_ccw_req *cqr)
 /*
  * Process ccw request queue.
  */
-static inline void
+static void
 __dasd_process_ccw_queue(struct dasd_device * device,
                         struct list_head *final_queue)
 {
@@ -1127,7 +1125,9 @@ restart:
                                cqr->status = DASD_CQR_FAILED;
                                cqr->stopclk = get_clock();
                        } else {
-                               if (cqr->irb.esw.esw0.erw.cons) {
+                               if (cqr->irb.esw.esw0.erw.cons &&
+                                   test_bit(DASD_CQR_FLAGS_USE_ERP,
+                                            &cqr->flags)) {
                                        erp_fn = device->discipline->
                                                erp_action(cqr);
                                        erp_fn(cqr);
@@ -1181,7 +1181,7 @@ dasd_end_request_cb(struct dasd_ccw_req * cqr, void *data)
 /*
  * Fetch requests from the block device queue.
  */
-static inline void
+static void
 __dasd_process_blk_queue(struct dasd_device * device)
 {
        request_queue_t *queue;
@@ -1232,6 +1232,19 @@ __dasd_process_blk_queue(struct dasd_device * device)
                if (IS_ERR(cqr)) {
                        if (PTR_ERR(cqr) == -ENOMEM)
                                break;  /* terminate request queue loop */
+                       if (PTR_ERR(cqr) == -EAGAIN) {
+                               /*
+                                * The current request cannot be build right
+                                * now, we have to try later. If this request
+                                * is the head-of-queue we stop the device
+                                * for 1/2 second.
+                                */
+                               if (!list_empty(&device->ccw_queue))
+                                       break;
+                               device->stopped |= DASD_STOPPED_PENDING;
+                               dasd_set_timer(device, HZ/2);
+                               break;
+                       }
                        DBF_DEV_EVENT(DBF_ERR, device,
                                      "CCW creation failed (rc=%ld) "
                                      "on request %p",
@@ -1254,7 +1267,7 @@ __dasd_process_blk_queue(struct dasd_device * device)
  * Take a look at the first request on the ccw queue and check
  * if it reached its expire time. If so, terminate the IO.
  */
-static inline void
+static void
 __dasd_check_expire(struct dasd_device * device)
 {
        struct dasd_ccw_req *cqr;
@@ -1285,7 +1298,7 @@ __dasd_check_expire(struct dasd_device * device)
  * Take a look at the first request on the ccw queue and check
  * if it needs to be started.
  */
-static inline void
+static void
 __dasd_start_head(struct dasd_device * device)
 {
        struct dasd_ccw_req *cqr;
index 4d01040..8b9d68f 100644 (file)
@@ -170,7 +170,6 @@ dasd_3990_erp_examine(struct dasd_ccw_req * cqr, struct irb * irb)
        /* log the erp chain if fatal error occurred */
        if ((era == dasd_era_fatal) && (device->state >= DASD_STATE_READY)) {
                dasd_log_sense(cqr, irb);
-               dasd_log_ccw(cqr, 0, irb->scsw.cpa);
        }
 
        return era;
@@ -2640,7 +2639,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
 
        struct dasd_ccw_req *erp = NULL;
        struct dasd_device *device = cqr->device;
-       __u32 cpa = cqr->irb.scsw.cpa;
        struct dasd_ccw_req *temp_erp = NULL;
 
        if (device->features & DASD_FEATURE_ERPLOG) {
@@ -2706,9 +2704,6 @@ dasd_3990_erp_action(struct dasd_ccw_req * cqr)
                }
        }
 
-       if (erp->status == DASD_CQR_FAILED)
-               dasd_log_ccw(erp, 1, cpa);
-
        /* enqueue added ERP request */
        if (erp->status == DASD_CQR_FILLED) {
                erp->status = DASD_CQR_QUEUED;
index 5943266..ed70852 100644 (file)
@@ -136,7 +136,7 @@ __setup ("dasd=", dasd_call_setup);
 /*
  * Read a device busid/devno from a string.
  */
-static inline int
+static int
 dasd_busid(char **str, int *id0, int *id1, int *devno)
 {
        int val, old_style;
@@ -182,7 +182,7 @@ dasd_busid(char **str, int *id0, int *id1, int *devno)
  * only one: "ro" for read-only devices. The default feature set
  * is empty (value 0).
  */
-static inline int
+static int
 dasd_feature_list(char *str, char **endp)
 {
        int features, len, rc;
@@ -341,7 +341,7 @@ dasd_parse_range( char *parsestring ) {
        return ERR_PTR(-EINVAL);
 }
 
-static inline char *
+static char *
 dasd_parse_next_element( char *parsestring ) {
        char * residual_str;
        residual_str = dasd_parse_keyword(parsestring);
index 53db58a..ab782bb 100644 (file)
@@ -43,7 +43,7 @@ MODULE_LICENSE("GPL");
 #define DIAG_MAX_RETRIES       32
 #define DIAG_TIMEOUT           50 * HZ
 
-struct dasd_discipline dasd_diag_discipline;
+static struct dasd_discipline dasd_diag_discipline;
 
 struct dasd_diag_private {
        struct dasd_diag_characteristics rdc_data;
@@ -90,7 +90,7 @@ static inline int dia250(void *iob, int cmd)
  * block offset. On success, return zero and set end_block to contain the
  * number of blocks on the device minus the specified offset. Return non-zero
  * otherwise. */
-static __inline__ int
+static inline int
 mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
             blocknum_t offset, blocknum_t *end_block)
 {
@@ -117,7 +117,7 @@ mdsk_init_io(struct dasd_device *device, unsigned int blocksize,
 
 /* Remove block I/O environment for device. Return zero on success, non-zero
  * otherwise. */
-static __inline__ int
+static inline int
 mdsk_term_io(struct dasd_device * device)
 {
        struct dasd_diag_private *private;
@@ -576,7 +576,7 @@ dasd_diag_dump_sense(struct dasd_device *device, struct dasd_ccw_req * req,
                    "dump sense not available for DIAG data");
 }
 
-struct dasd_discipline dasd_diag_discipline = {
+static struct dasd_discipline dasd_diag_discipline = {
        .owner = THIS_MODULE,
        .name = "DIAG",
        .ebcname = "DIAG",
index fdaa471..cecab22 100644 (file)
@@ -134,44 +134,7 @@ ceil_quot(unsigned int d1, unsigned int d2)
        return (d1 + (d2 - 1)) / d2;
 }
 
-static inline int
-bytes_per_record(struct dasd_eckd_characteristics *rdc, int kl, int dl)
-{
-       unsigned int fl1, fl2, int1, int2;
-       int bpr;
-
-       switch (rdc->formula) {
-       case 0x01:
-               fl1 = round_up_multiple(ECKD_F2(rdc) + dl, ECKD_F1(rdc));
-               fl2 = round_up_multiple(kl ? ECKD_F2(rdc) + kl : 0,
-                                       ECKD_F1(rdc));
-               bpr = fl1 + fl2;
-               break;
-       case 0x02:
-               int1 = ceil_quot(dl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
-               int2 = ceil_quot(kl + ECKD_F6(rdc), ECKD_F5(rdc) << 1);
-               fl1 = round_up_multiple(ECKD_F1(rdc) * ECKD_F2(rdc) + dl +
-                                       ECKD_F6(rdc) + ECKD_F4(rdc) * int1,
-                                       ECKD_F1(rdc));
-               fl2 = round_up_multiple(ECKD_F1(rdc) * ECKD_F3(rdc) + kl +
-                                       ECKD_F6(rdc) + ECKD_F4(rdc) * int2,
-                                       ECKD_F1(rdc));
-               bpr = fl1 + fl2;
-               break;
-       default:
-               bpr = 0;
-               break;
-       }
-       return bpr;
-}
-
-static inline unsigned int
-bytes_per_track(struct dasd_eckd_characteristics *rdc)
-{
-       return *(unsigned int *) (rdc->byte_per_track) >> 8;
-}
-
-static inline unsigned int
+static unsigned int
 recs_per_track(struct dasd_eckd_characteristics * rdc,
               unsigned int kl, unsigned int dl)
 {
@@ -204,37 +167,39 @@ recs_per_track(struct dasd_eckd_characteristics * rdc,
        return 0;
 }
 
-static inline void
+static int
 check_XRC (struct ccw1         *de_ccw,
            struct DE_eckd_data *data,
            struct dasd_device  *device)
 {
         struct dasd_eckd_private *private;
+       int rc;
 
         private = (struct dasd_eckd_private *) device->private;
+       if (!private->rdc_data.facilities.XRC_supported)
+               return 0;
 
         /* switch on System Time Stamp - needed for XRC Support */
-        if (private->rdc_data.facilities.XRC_supported) {
-
-                data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid'   */
-                data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
-
-                data->ep_sys_time = get_clock ();
-
-                de_ccw->count = sizeof (struct DE_eckd_data);
-               de_ccw->flags |= CCW_FLAG_SLI;
-        }
+       data->ga_extended |= 0x08; /* switch on 'Time Stamp Valid'   */
+       data->ga_extended |= 0x02; /* switch on 'Extended Parameter' */
 
-        return;
+       rc = get_sync_clock(&data->ep_sys_time);
+       /* Ignore return code if sync clock is switched off. */
+       if (rc == -ENOSYS || rc == -EACCES)
+               rc = 0;
 
-} /* end check_XRC */
+       de_ccw->count = sizeof (struct DE_eckd_data);
+       de_ccw->flags |= CCW_FLAG_SLI;
+       return rc;
+}
 
-static inline void
+static int
 define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
              int totrk, int cmd, struct dasd_device * device)
 {
        struct dasd_eckd_private *private;
        struct ch_t geo, beg, end;
+       int rc = 0;
 
        private = (struct dasd_eckd_private *) device->private;
 
@@ -263,12 +228,12 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
        case DASD_ECKD_CCW_WRITE_KD_MT:
                data->mask.perm = 0x02;
                data->attributes.operation = private->attrib.operation;
-                check_XRC (ccw, data, device);
+               rc = check_XRC (ccw, data, device);
                break;
        case DASD_ECKD_CCW_WRITE_CKD:
        case DASD_ECKD_CCW_WRITE_CKD_MT:
                data->attributes.operation = DASD_BYPASS_CACHE;
-                check_XRC (ccw, data, device);
+               rc = check_XRC (ccw, data, device);
                break;
        case DASD_ECKD_CCW_ERASE:
        case DASD_ECKD_CCW_WRITE_HOME_ADDRESS:
@@ -276,7 +241,7 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
                data->mask.perm = 0x3;
                data->mask.auth = 0x1;
                data->attributes.operation = DASD_BYPASS_CACHE;
-                check_XRC (ccw, data, device);
+               rc = check_XRC (ccw, data, device);
                break;
        default:
                DEV_MESSAGE(KERN_ERR, device, "unknown opcode 0x%x", cmd);
@@ -312,9 +277,10 @@ define_extent(struct ccw1 * ccw, struct DE_eckd_data * data, int trk,
        data->beg_ext.head = beg.head;
        data->end_ext.cyl = end.cyl;
        data->end_ext.head = end.head;
+       return rc;
 }
 
-static inline void
+static void
 locate_record(struct ccw1 *ccw, struct LO_eckd_data *data, int trk,
              int rec_on_trk, int no_rec, int cmd,
              struct dasd_device * device, int reclen)
@@ -548,7 +514,7 @@ dasd_eckd_read_conf(struct dasd_device *device)
 /*
  * Build CP for Perform Subsystem Function - SSC.
  */
-struct dasd_ccw_req *
+static struct dasd_ccw_req *
 dasd_eckd_build_psf_ssc(struct dasd_device *device)
 {
        struct dasd_ccw_req *cqr;
@@ -1200,7 +1166,12 @@ dasd_eckd_build_cp(struct dasd_device * device, struct request *req)
                return cqr;
        ccw = cqr->cpaddr;
        /* First ccw is define extent. */
-       define_extent(ccw++, cqr->data, first_trk, last_trk, cmd, device);
+       if (define_extent(ccw++, cqr->data, first_trk,
+                         last_trk, cmd, device) == -EAGAIN) {
+               /* Clock not in sync and XRC is enabled. Try again later. */
+               dasd_sfree_request(cqr, device);
+               return ERR_PTR(-EAGAIN);
+       }
        /* Build locate_record+read/write/ccws. */
        idaws = (unsigned long *) (cqr->data + sizeof(struct DE_eckd_data));
        LO_data = (struct LO_eckd_data *) (idaws + cidaw);
@@ -1380,7 +1351,7 @@ dasd_eckd_release(struct dasd_device *device)
        cqr->device = device;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
        set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-       cqr->retries = 0;
+       cqr->retries = 2;       /* set retry counter to enable basic ERP */
        cqr->expires = 2 * HZ;
        cqr->buildclk = get_clock();
        cqr->status = DASD_CQR_FILLED;
@@ -1420,7 +1391,7 @@ dasd_eckd_reserve(struct dasd_device *device)
        cqr->device = device;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
        set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-       cqr->retries = 0;
+       cqr->retries = 2;       /* set retry counter to enable basic ERP */
        cqr->expires = 2 * HZ;
        cqr->buildclk = get_clock();
        cqr->status = DASD_CQR_FILLED;
@@ -1459,7 +1430,7 @@ dasd_eckd_steal_lock(struct dasd_device *device)
        cqr->device = device;
        clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
        set_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags);
-       cqr->retries = 0;
+       cqr->retries = 2;       /* set retry counter to enable basic ERP */
        cqr->expires = 2 * HZ;
        cqr->buildclk = get_clock();
        cqr->status = DASD_CQR_FILLED;
@@ -1609,7 +1580,7 @@ dasd_eckd_ioctl(struct dasd_device *device, unsigned int cmd, void __user *argp)
  * Dump the range of CCWs into 'page' buffer
  * and return number of printed chars.
  */
-static inline int
+static int
 dasd_eckd_dump_ccw_range(struct ccw1 *from, struct ccw1 *to, char *page)
 {
        int len, count;
index e0bf30e..6cedc91 100644 (file)
@@ -658,18 +658,24 @@ static struct file_operations dasd_eer_fops = {
        .owner          = THIS_MODULE,
 };
 
-static struct miscdevice dasd_eer_dev = {
-       .minor      = MISC_DYNAMIC_MINOR,
-       .name       = "dasd_eer",
-       .fops       = &dasd_eer_fops,
-};
+static struct miscdevice *dasd_eer_dev = NULL;
 
 int __init dasd_eer_init(void)
 {
        int rc;
 
-       rc = misc_register(&dasd_eer_dev);
+       dasd_eer_dev = kzalloc(sizeof(*dasd_eer_dev), GFP_KERNEL);
+       if (!dasd_eer_dev)
+               return -ENOMEM;
+
+       dasd_eer_dev->minor = MISC_DYNAMIC_MINOR;
+       dasd_eer_dev->name  = "dasd_eer";
+       dasd_eer_dev->fops  = &dasd_eer_fops;
+
+       rc = misc_register(dasd_eer_dev);
        if (rc) {
+               kfree(dasd_eer_dev);
+               dasd_eer_dev = NULL;
                MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
                       "register misc device");
                return rc;
@@ -680,5 +686,9 @@ int __init dasd_eer_init(void)
 
 void dasd_eer_exit(void)
 {
-       WARN_ON(misc_deregister(&dasd_eer_dev) != 0);
+       if (dasd_eer_dev) {
+               WARN_ON(misc_deregister(dasd_eer_dev) != 0);
+               kfree(dasd_eer_dev);
+               dasd_eer_dev = NULL;
+       }
 }
index 58a6509..caa5d91 100644 (file)
@@ -152,25 +152,6 @@ dasd_default_erp_postaction(struct dasd_ccw_req * cqr)
 
 }                              /* end default_erp_postaction */
 
-/*
- * Print the hex dump of the memory used by a request. This includes
- * all error recovery ccws that have been chained in from of the
- * real request.
- */
-static inline void
-hex_dump_memory(struct dasd_device *device, void *data, int len)
-{
-       int *pint;
-
-       pint = (int *) data;
-       while (len > 0) {
-               DEV_MESSAGE(KERN_ERR, device, "%p: %08x %08x %08x %08x",
-                           pint, pint[0], pint[1], pint[2], pint[3]);
-               pint += 4;
-               len -= 16;
-       }
-}
-
 void
 dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
 {
@@ -182,69 +163,8 @@ dasd_log_sense(struct dasd_ccw_req *cqr, struct irb *irb)
                device->discipline->dump_sense(device, cqr, irb);
 }
 
-void
-dasd_log_ccw(struct dasd_ccw_req * cqr, int caller, __u32 cpa)
-{
-       struct dasd_device *device;
-       struct dasd_ccw_req *lcqr;
-       struct ccw1 *ccw;
-       int cplength;
-
-       device = cqr->device;
-       /* log the channel program */
-       for (lcqr = cqr; lcqr != NULL; lcqr = lcqr->refers) {
-               DEV_MESSAGE(KERN_ERR, device,
-                           "(%s) ERP chain report for req: %p",
-                           caller == 0 ? "EXAMINE" : "ACTION", lcqr);
-               hex_dump_memory(device, lcqr, sizeof(struct dasd_ccw_req));
-
-               cplength = 1;
-               ccw = lcqr->cpaddr;
-               while (ccw++->flags & (CCW_FLAG_DC | CCW_FLAG_CC))
-                       cplength++;
-
-               if (cplength > 40) {    /* log only parts of the CP */
-                       DEV_MESSAGE(KERN_ERR, device, "%s",
-                                   "Start of channel program:");
-                       hex_dump_memory(device, lcqr->cpaddr,
-                                       40*sizeof(struct ccw1));
-
-                       DEV_MESSAGE(KERN_ERR, device, "%s",
-                                   "End of channel program:");
-                       hex_dump_memory(device, lcqr->cpaddr + cplength - 10,
-                                       10*sizeof(struct ccw1));
-               } else {        /* log the whole CP */
-                       DEV_MESSAGE(KERN_ERR, device, "%s",
-                                   "Channel program (complete):");
-                       hex_dump_memory(device, lcqr->cpaddr,
-                                       cplength*sizeof(struct ccw1));
-               }
-
-               if (lcqr != cqr)
-                       continue;
-
-               /*
-                * Log bytes arround failed CCW but only if we did
-                * not log the whole CP of the CCW is outside the
-                * logged CP.
-                */
-               if (cplength > 40 ||
-                   ((addr_t) cpa < (addr_t) lcqr->cpaddr &&
-                    (addr_t) cpa > (addr_t) (lcqr->cpaddr + cplength + 4))) {
-
-                       DEV_MESSAGE(KERN_ERR, device,
-                                   "Failed CCW (%p) (area):",
-                                   (void *) (long) cpa);
-                       hex_dump_memory(device, cqr->cpaddr - 10,
-                                       20*sizeof(struct ccw1));
-               }
-       }
-
-}                              /* end log_erp_chain */
-
 EXPORT_SYMBOL(dasd_default_erp_action);
 EXPORT_SYMBOL(dasd_default_erp_postaction);
 EXPORT_SYMBOL(dasd_alloc_erp_request);
 EXPORT_SYMBOL(dasd_free_erp_request);
 EXPORT_SYMBOL(dasd_log_sense);
-EXPORT_SYMBOL(dasd_log_ccw);
index b857fd5..be0909e 100644 (file)
@@ -75,7 +75,7 @@ static struct ccw_driver dasd_fba_driver = {
        .notify      = dasd_generic_notify,
 };
 
-static inline void
+static void
 define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
              int blksize, int beg, int nr)
 {
@@ -95,7 +95,7 @@ define_extent(struct ccw1 * ccw, struct DE_fba_data *data, int rw,
        data->ext_end = nr - 1;
 }
 
-static inline void
+static void
 locate_record(struct ccw1 * ccw, struct LO_fba_data *data, int rw,
              int block_nr, int block_ct)
 {
index d163632..47ba446 100644 (file)
@@ -147,7 +147,7 @@ dasd_destroy_partitions(struct dasd_device * device)
         */
        memset(&bpart, 0, sizeof(struct blkpg_partition));
        memset(&barg, 0, sizeof(struct blkpg_ioctl_arg));
-       barg.data = (void __user *) &bpart;
+       barg.data = (void __force __user *) &bpart;
        barg.op = BLKPG_DEL_PARTITION;
        for (bpart.pno = device->gdp->minors - 1; bpart.pno > 0; bpart.pno--)
                ioctl_by_bdev(bdev, BLKPG, (unsigned long) &barg);
index fb725e3..a2cc69e 100644 (file)
@@ -559,7 +559,6 @@ struct dasd_ccw_req *dasd_alloc_erp_request(char *, int, int,
                                            struct dasd_device *);
 void dasd_free_erp_request(struct dasd_ccw_req *, struct dasd_device *);
 void dasd_log_sense(struct dasd_ccw_req *, struct irb *);
-void dasd_log_ccw(struct dasd_ccw_req *, int, __u32);
 
 /* externals in dasd_3370_erp.c */
 dasd_era_t dasd_3370_erp_examine(struct dasd_ccw_req *, struct irb *);
index bfa010f..8b7e118 100644 (file)
@@ -28,7 +28,7 @@ static struct proc_dir_entry *dasd_proc_root_entry = NULL;
 static struct proc_dir_entry *dasd_devices_entry = NULL;
 static struct proc_dir_entry *dasd_statistics_entry = NULL;
 
-static inline char *
+static char *
 dasd_get_user_string(const char __user *user_buf, size_t user_len)
 {
        char *buffer;
@@ -154,7 +154,7 @@ static struct file_operations dasd_devices_file_ops = {
        .release        = seq_release,
 };
 
-static inline int
+static int
 dasd_calc_metrics(char *page, char **start, off_t off,
                  int count, int *eof, int len)
 {
@@ -167,8 +167,8 @@ dasd_calc_metrics(char *page, char **start, off_t off,
        return len;
 }
 
-static inline char *
-dasd_statistics_array(char *str, int *array, int shift)
+static char *
+dasd_statistics_array(char *str, unsigned int *array, int shift)
 {
        int i;
 
index be9b053..1340451 100644 (file)
@@ -102,7 +102,7 @@ dcssblk_release_segment(struct device *dev)
  * device needs to be enqueued before the semaphore is
  * freed.
  */
-static inline int
+static int
 dcssblk_assign_free_minor(struct dcssblk_dev_info *dev_info)
 {
        int minor, found;
@@ -230,7 +230,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
                                           SEGMENT_SHARED);
                if (rc < 0) {
                        BUG_ON(rc == -EINVAL);
-                       if (rc == -EIO || rc == -ENOENT)
+                       if (rc != -EAGAIN)
                                goto removeseg;
                } else {
                        dev_info->is_shared = 1;
@@ -253,7 +253,7 @@ dcssblk_shared_store(struct device *dev, struct device_attribute *attr, const ch
                                           SEGMENT_EXCLUSIVE);
                if (rc < 0) {
                        BUG_ON(rc == -EINVAL);
-                       if (rc == -EIO || rc == -ENOENT)
+                       if (rc != -EAGAIN)
                                goto removeseg;
                } else {
                        dev_info->is_shared = 0;
index c3e97b4..293e667 100644 (file)
@@ -2,7 +2,8 @@
 # S/390 character devices
 #
 
-obj-y += ctrlchar.o keyboard.o defkeymap.o
+obj-y += ctrlchar.o keyboard.o defkeymap.o sclp.o sclp_rw.o sclp_quiesce.o \
+        sclp_info.o
 
 obj-$(CONFIG_TN3270) += raw3270.o
 obj-$(CONFIG_TN3270_CONSOLE) += con3270.o
@@ -11,7 +12,6 @@ obj-$(CONFIG_TN3270_FS) += fs3270.o
 
 obj-$(CONFIG_TN3215) += con3215.o
 
-obj-$(CONFIG_SCLP) += sclp.o sclp_rw.o sclp_quiesce.o
 obj-$(CONFIG_SCLP_TTY) += sclp_tty.o
 obj-$(CONFIG_SCLP_CONSOLE) += sclp_con.o
 obj-$(CONFIG_SCLP_VT220_TTY) += sclp_vt220.o
index 25b5d7a..9a328f1 100644 (file)
@@ -1121,7 +1121,7 @@ static const struct tty_operations tty3215_ops = {
  * 3215 tty registration code called from tty_init().
  * Most kernel services (incl. kmalloc) are available at this poimt.
  */
-int __init
+static int __init
 tty3215_init(void)
 {
        struct tty_driver *driver;
index 7566be8..8e7f2d7 100644 (file)
@@ -69,8 +69,7 @@ static void con3270_update(struct con3270 *);
 /*
  * Setup timeout for a device. On timeout trigger an update.
  */
-void
-con3270_set_timer(struct con3270 *cp, int expires)
+static void con3270_set_timer(struct con3270 *cp, int expires)
 {
        if (expires == 0) {
                if (timer_pending(&cp->timer))
index 17027d9..564baca 100644 (file)
@@ -5,6 +5,8 @@
 #include <linux/types.h>
 #include <linux/keyboard.h>
 #include <linux/kd.h>
+#include <linux/kbd_kern.h>
+#include <linux/kbd_diacr.h>
 
 u_short plain_map[NR_KEYS] = {
        0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000, 0xf000,
index 0893d30..e1a7462 100644 (file)
@@ -23,7 +23,7 @@
 #include "raw3270.h"
 #include "ctrlchar.h"
 
-struct raw3270_fn fs3270_fn;
+static struct raw3270_fn fs3270_fn;
 
 struct fs3270 {
        struct raw3270_view view;
@@ -401,7 +401,7 @@ fs3270_release(struct raw3270_view *view)
 }
 
 /* View to a 3270 device. Can be console, tty or fullscreen. */
-struct raw3270_fn fs3270_fn = {
+static struct raw3270_fn fs3270_fn = {
        .activate = fs3270_activate,
        .deactivate = fs3270_deactivate,
        .intv = (void *) fs3270_irq,
index 3e86fd1..f62f9a4 100644 (file)
@@ -148,6 +148,7 @@ kbd_ascebc(struct kbd_data *kbd, unsigned char *ascebc)
        }
 }
 
+#if 0
 /*
  * Generate ebcdic -> ascii translation table from kbd_data.
  */
@@ -173,6 +174,7 @@ kbd_ebcasc(struct kbd_data *kbd, unsigned char *ebcasc)
                }
        }
 }
+#endif
 
 /*
  * We have a combining character DIACR here, followed by the character CH.
index cdb24f5..9e451ac 100644 (file)
@@ -67,8 +67,8 @@ static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn)
        return -EINVAL;
 }
 
-static inline struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
-                                               struct monwrite_hdr *monhdr)
+static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv,
+                                        struct monwrite_hdr *monhdr)
 {
        struct mon_buf *entry, *next;
 
index 7a84014..8facd14 100644 (file)
@@ -29,7 +29,7 @@
 #include <linux/device.h>
 #include <linux/mutex.h>
 
-struct class *class3270;
+static struct class *class3270;
 
 /* The main 3270 data structure. */
 struct raw3270 {
@@ -86,7 +86,7 @@ DECLARE_WAIT_QUEUE_HEAD(raw3270_wait_queue);
 /*
  * Encode array for 12 bit 3270 addresses.
  */
-unsigned char raw3270_ebcgraf[64] =    {
+static unsigned char raw3270_ebcgraf[64] =     {
        0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
        0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
        0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
index 8a056df..f171de3 100644 (file)
@@ -59,7 +59,8 @@ static volatile enum sclp_init_state_t {
 /* Internal state: is a request active at the sclp? */
 static volatile enum sclp_running_state_t {
        sclp_running_state_idle,
-       sclp_running_state_running
+       sclp_running_state_running,
+       sclp_running_state_reset_pending
 } sclp_running_state = sclp_running_state_idle;
 
 /* Internal state: is a read request pending? */
@@ -88,15 +89,15 @@ static volatile enum sclp_mask_state_t {
 
 /* Timeout intervals in seconds.*/
 #define SCLP_BUSY_INTERVAL     10
-#define SCLP_RETRY_INTERVAL    15
+#define SCLP_RETRY_INTERVAL    30
 
 static void sclp_process_queue(void);
 static int sclp_init_mask(int calculate);
 static int sclp_init(void);
 
 /* Perform service call. Return 0 on success, non-zero otherwise. */
-static int
-service_call(sclp_cmdw_t command, void *sccb)
+int
+sclp_service_call(sclp_cmdw_t command, void *sccb)
 {
        int cc;
 
@@ -113,19 +114,17 @@ service_call(sclp_cmdw_t command, void *sccb)
        return 0;
 }
 
-/* Request timeout handler. Restart the request queue. If DATA is non-zero,
- * force restart of running request. */
+static inline void __sclp_make_read_req(void);
+
 static void
-sclp_request_timeout(unsigned long data)
+__sclp_queue_read_req(void)
 {
-       unsigned long flags;
-
-       if (data) {
-               spin_lock_irqsave(&sclp_lock, flags);
-               sclp_running_state = sclp_running_state_idle;
-               spin_unlock_irqrestore(&sclp_lock, flags);
+       if (sclp_reading_state == sclp_reading_state_idle) {
+               sclp_reading_state = sclp_reading_state_reading;
+               __sclp_make_read_req();
+               /* Add request to head of queue */
+               list_add(&sclp_read_req.list, &sclp_req_queue);
        }
-       sclp_process_queue();
 }
 
 /* Set up request retry timer. Called while sclp_lock is locked. */
@@ -140,6 +139,29 @@ __sclp_set_request_timer(unsigned long time, void (*function)(unsigned long),
        add_timer(&sclp_request_timer);
 }
 
+/* Request timeout handler. Restart the request queue. If DATA is non-zero,
+ * force restart of running request. */
+static void
+sclp_request_timeout(unsigned long data)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&sclp_lock, flags);
+       if (data) {
+               if (sclp_running_state == sclp_running_state_running) {
+                       /* Break running state and queue NOP read event request
+                        * to get a defined interface state. */
+                       __sclp_queue_read_req();
+                       sclp_running_state = sclp_running_state_idle;
+               }
+       } else {
+               __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
+                                        sclp_request_timeout, 0);
+       }
+       spin_unlock_irqrestore(&sclp_lock, flags);
+       sclp_process_queue();
+}
+
 /* Try to start a request. Return zero if the request was successfully
  * started or if it will be started at a later time. Return non-zero otherwise.
  * Called while sclp_lock is locked. */
@@ -151,7 +173,7 @@ __sclp_start_request(struct sclp_req *req)
        if (sclp_running_state != sclp_running_state_idle)
                return 0;
        del_timer(&sclp_request_timer);
-       rc = service_call(req->command, req->sccb);
+       rc = sclp_service_call(req->command, req->sccb);
        req->start_count++;
 
        if (rc == 0) {
@@ -191,7 +213,15 @@ sclp_process_queue(void)
                rc = __sclp_start_request(req);
                if (rc == 0)
                        break;
-               /* Request failed. */
+               /* Request failed */
+               if (req->start_count > 1) {
+                       /* Cannot abort already submitted request - could still
+                        * be active at the SCLP */
+                       __sclp_set_request_timer(SCLP_BUSY_INTERVAL * HZ,
+                                                sclp_request_timeout, 0);
+                       break;
+               }
+               /* Post-processing for aborted request */
                list_del(&req->list);
                if (req->callback) {
                        spin_unlock_irqrestore(&sclp_lock, flags);
@@ -221,7 +251,8 @@ sclp_add_request(struct sclp_req *req)
        list_add_tail(&req->list, &sclp_req_queue);
        rc = 0;
        /* Start if request is first in list */
-       if (req->list.prev == &sclp_req_queue) {
+       if (sclp_running_state == sclp_running_state_idle &&
+           req->list.prev == &sclp_req_queue) {
                rc = __sclp_start_request(req);
                if (rc)
                        list_del(&req->list);
@@ -294,7 +325,7 @@ __sclp_make_read_req(void)
        sccb = (struct sccb_header *) sclp_read_sccb;
        clear_page(sccb);
        memset(&sclp_read_req, 0, sizeof(struct sclp_req));
-       sclp_read_req.command = SCLP_CMDW_READDATA;
+       sclp_read_req.command = SCLP_CMDW_READ_EVENT_DATA;
        sclp_read_req.status = SCLP_REQ_QUEUED;
        sclp_read_req.start_count = 0;
        sclp_read_req.callback = sclp_read_cb;
@@ -334,6 +365,8 @@ sclp_interrupt_handler(__u16 code)
        finished_sccb = S390_lowcore.ext_params & 0xfffffff8;
        evbuf_pending = S390_lowcore.ext_params & 0x3;
        if (finished_sccb) {
+               del_timer(&sclp_request_timer);
+               sclp_running_state = sclp_running_state_reset_pending;
                req = __sclp_find_req(finished_sccb);
                if (req) {
                        /* Request post-processing */
@@ -348,13 +381,8 @@ sclp_interrupt_handler(__u16 code)
                sclp_running_state = sclp_running_state_idle;
        }
        if (evbuf_pending && sclp_receive_mask != 0 &&
-           sclp_reading_state == sclp_reading_state_idle &&
-           sclp_activation_state == sclp_activation_state_active ) {
-               sclp_reading_state = sclp_reading_state_reading;
-               __sclp_make_read_req();
-               /* Add request to head of queue */
-               list_add(&sclp_read_req.list, &sclp_req_queue);
-       }
+           sclp_activation_state == sclp_activation_state_active)
+               __sclp_queue_read_req();
        spin_unlock(&sclp_lock);
        sclp_process_queue();
 }
@@ -374,6 +402,7 @@ sclp_sync_wait(void)
        unsigned long flags;
        unsigned long cr0, cr0_sync;
        u64 timeout;
+       int irq_context;
 
        /* We'll be disabling timer interrupts, so we need a custom timeout
         * mechanism */
@@ -386,7 +415,9 @@ sclp_sync_wait(void)
        }
        local_irq_save(flags);
        /* Prevent bottom half from executing once we force interrupts open */
-       local_bh_disable();
+       irq_context = in_interrupt();
+       if (!irq_context)
+               local_bh_disable();
        /* Enable service-signal interruption, disable timer interrupts */
        trace_hardirqs_on();
        __ctl_store(cr0, 0, 0);
@@ -402,19 +433,19 @@ sclp_sync_wait(void)
                    get_clock() > timeout &&
                    del_timer(&sclp_request_timer))
                        sclp_request_timer.function(sclp_request_timer.data);
-               barrier();
                cpu_relax();
        }
        local_irq_disable();
        __ctl_load(cr0, 0, 0);
-       _local_bh_enable();
+       if (!irq_context)
+               _local_bh_enable();
        local_irq_restore(flags);
 }
 
 EXPORT_SYMBOL(sclp_sync_wait);
 
 /* Dispatch changes in send and receive mask to registered listeners. */
-static inline void
+static void
 sclp_dispatch_state_change(void)
 {
        struct list_head *l;
@@ -597,7 +628,7 @@ __sclp_make_init_req(u32 receive_mask, u32 send_mask)
        sccb = (struct init_sccb *) sclp_init_sccb;
        clear_page(sccb);
        memset(&sclp_init_req, 0, sizeof(struct sclp_req));
-       sclp_init_req.command = SCLP_CMDW_WRITEMASK;
+       sclp_init_req.command = SCLP_CMDW_WRITE_EVENT_MASK;
        sclp_init_req.status = SCLP_REQ_FILLED;
        sclp_init_req.start_count = 0;
        sclp_init_req.callback = NULL;
@@ -800,7 +831,7 @@ sclp_check_interface(void)
        for (retry = 0; retry <= SCLP_INIT_RETRY; retry++) {
                __sclp_make_init_req(0, 0);
                sccb = (struct init_sccb *) sclp_init_req.sccb;
-               rc = service_call(sclp_init_req.command, sccb);
+               rc = sclp_service_call(sclp_init_req.command, sccb);
                if (rc == -EIO)
                        break;
                sclp_init_req.status = SCLP_REQ_RUNNING;
index 2c71d6e..7d29ab4 100644 (file)
@@ -12,7 +12,7 @@
 
 #include <linux/types.h>
 #include <linux/list.h>
-
+#include <asm/sclp.h>
 #include <asm/ebcdic.h>
 
 /* maximum number of pages concerning our own memory management */
 
 typedef unsigned int sclp_cmdw_t;
 
-#define SCLP_CMDW_READDATA     0x00770005
-#define SCLP_CMDW_WRITEDATA    0x00760005
-#define SCLP_CMDW_WRITEMASK    0x00780005
+#define SCLP_CMDW_READ_EVENT_DATA      0x00770005
+#define SCLP_CMDW_WRITE_EVENT_DATA     0x00760005
+#define SCLP_CMDW_WRITE_EVENT_MASK     0x00780005
+#define SCLP_CMDW_READ_SCP_INFO                0x00020001
+#define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
 
 #define GDS_ID_MDSMU           0x1310
 #define GDS_ID_MDSRouteInfo    0x1311
@@ -66,13 +68,6 @@ typedef unsigned int sclp_cmdw_t;
 
 typedef u32 sccb_mask_t;       /* ATTENTION: assumes 32bit mask !!! */
 
-struct sccb_header {
-       u16     length;
-       u8      function_code;
-       u8      control_mask[3];
-       u16     response_code;
-} __attribute__((packed));
-
 struct gds_subvector {
        u8      length;
        u8      key;
@@ -131,6 +126,7 @@ void sclp_unregister(struct sclp_register *reg);
 int sclp_remove_processed(struct sccb_header *sccb);
 int sclp_deactivate(void);
 int sclp_reactivate(void);
+int sclp_service_call(sclp_cmdw_t command, void *sccb);
 
 /* useful inlines */
 
index 86864f6..ead1043 100644 (file)
@@ -66,7 +66,7 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
        } while (buffer && sclp_emit_buffer(buffer, sclp_conbuf_callback));
 }
 
-static inline void
+static void
 sclp_conbuf_emit(void)
 {
        struct sclp_buffer* buffer;
index 4f873ae..65aa2c8 100644 (file)
@@ -169,7 +169,7 @@ cpi_prepare_req(void)
        }
 
        /* prepare request data structure presented to SCLP driver */
-       req->command = SCLP_CMDW_WRITEDATA;
+       req->command = SCLP_CMDW_WRITE_EVENT_DATA;
        req->sccb = sccb;
        req->status = SCLP_REQ_FILLED;
        req->callback = cpi_callback;
diff --git a/drivers/s390/char/sclp_info.c b/drivers/s390/char/sclp_info.c
new file mode 100644 (file)
index 0000000..7bcbe64
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ *  drivers/s390/char/sclp_info.c
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <asm/sclp.h>
+#include "sclp.h"
+
+struct sclp_readinfo_sccb s390_readinfo_sccb;
+
+void __init sclp_readinfo_early(void)
+{
+       sclp_cmdw_t command;
+       struct sccb_header *sccb;
+       int ret;
+
+       __ctl_set_bit(0, 9); /* enable service signal subclass mask */
+
+       sccb = &s390_readinfo_sccb.header;
+       command = SCLP_CMDW_READ_SCP_INFO_FORCED;
+       while (1) {
+               u16 response;
+
+               memset(&s390_readinfo_sccb, 0, sizeof(s390_readinfo_sccb));
+               sccb->length = sizeof(s390_readinfo_sccb);
+               sccb->control_mask[2] = 0x80;
+
+               ret = sclp_service_call(command, &s390_readinfo_sccb);
+
+               if (ret == -EIO)
+                       goto out;
+               if (ret == -EBUSY)
+                       continue;
+
+               __load_psw_mask(PSW_BASE_BITS | PSW_MASK_EXT |
+                               PSW_MASK_WAIT | PSW_DEFAULT_KEY);
+               local_irq_disable();
+               barrier();
+
+               response = sccb->response_code;
+
+               if (response == 0x10)
+                       break;
+
+               if (response != 0x1f0 || command == SCLP_CMDW_READ_SCP_INFO)
+                       break;
+
+               command = SCLP_CMDW_READ_SCP_INFO;
+       }
+out:
+       __ctl_clear_bit(0, 9); /* disable service signal subclass mask */
+}
index 0c92d39..2486783 100644 (file)
@@ -460,7 +460,7 @@ sclp_emit_buffer(struct sclp_buffer *buffer,
                sccb->msg_buf.header.type = EvTyp_PMsgCmd;
        else
                return -ENOSYS;
-       buffer->request.command = SCLP_CMDW_WRITEDATA;
+       buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
        buffer->request.status = SCLP_REQ_FILLED;
        buffer->request.callback = sclp_writedata_callback;
        buffer->request.callback_data = buffer;
index 2d173e5..90536f6 100644 (file)
@@ -721,7 +721,7 @@ static const struct tty_operations sclp_ops = {
        .ioctl = sclp_tty_ioctl,
 };
 
-int __init
+static int __init
 sclp_tty_init(void)
 {
        struct tty_driver *driver;
index 723bf41..544f137 100644 (file)
@@ -207,7 +207,7 @@ __sclp_vt220_emit(struct sclp_vt220_request *request)
                request->sclp_req.status = SCLP_REQ_FAILED;
                return -EIO;
        }
-       request->sclp_req.command = SCLP_CMDW_WRITEDATA;
+       request->sclp_req.command = SCLP_CMDW_WRITE_EVENT_DATA;
        request->sclp_req.status = SCLP_REQ_FILLED;
        request->sclp_req.callback = sclp_vt220_callback;
        request->sclp_req.callback_data = (void *) request;
@@ -669,7 +669,7 @@ static const struct tty_operations sclp_vt220_ops = {
 /*
  * Register driver with SCLP and Linux and initialize internal tty structures.
  */
-int __init
+static int __init
 sclp_vt220_tty_init(void)
 {
        struct tty_driver *driver;
index c9f1c4c..bb4ff53 100644 (file)
@@ -3,7 +3,7 @@
  *    tape device driver for 3480/3490E/3590 tapes.
  *
  *  S390 and zSeries version
- *    Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 2001,2006
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *              Tuan Ngo-Anh <ngoanh@de.ibm.com>
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -99,7 +99,11 @@ enum tape_op {
        TO_DIS,         /* Tape display */
        TO_ASSIGN,      /* Assign tape to channel path */
        TO_UNASSIGN,    /* Unassign tape from channel path */
-       TO_SIZE         /* #entries in tape_op_t */
+       TO_CRYPT_ON,    /* Enable encrpytion */
+       TO_CRYPT_OFF,   /* Disable encrpytion */
+       TO_KEKL_SET,    /* Set KEK label */
+       TO_KEKL_QUERY,  /* Query KEK label */
+       TO_SIZE,        /* #entries in tape_op_t */
 };
 
 /* Forward declaration */
@@ -112,6 +116,7 @@ enum tape_request_status {
        TAPE_REQUEST_IN_IO,     /* request is currently in IO */
        TAPE_REQUEST_DONE,      /* request is completed. */
        TAPE_REQUEST_CANCEL,    /* request should be canceled. */
+       TAPE_REQUEST_LONG_BUSY, /* request has to be restarted after long busy */
 };
 
 /* Tape CCW request */
@@ -164,10 +169,11 @@ struct tape_discipline {
  * The discipline irq function either returns an error code (<0) which
  * means that the request has failed with an error or one of the following:
  */
-#define TAPE_IO_SUCCESS 0      /* request successful */
-#define TAPE_IO_PENDING 1      /* request still running */
-#define TAPE_IO_RETRY  2       /* retry to current request */
-#define TAPE_IO_STOP   3       /* stop the running request */
+#define TAPE_IO_SUCCESS                0       /* request successful */
+#define TAPE_IO_PENDING                1       /* request still running */
+#define TAPE_IO_RETRY          2       /* retry to current request */
+#define TAPE_IO_STOP           3       /* stop the running request */
+#define TAPE_IO_LONG_BUSY      4       /* delay the running request */
 
 /* Char Frontend Data */
 struct tape_char_data {
@@ -242,6 +248,10 @@ struct tape_device {
 
        /* Function to start or stop the next request later. */
        struct delayed_work             tape_dnr;
+
+       /* Timer for long busy */
+       struct timer_list               lb_timeout;
+
 };
 
 /* Externals from tape_core.c */
index 9df912f..50f5eda 100644 (file)
@@ -2,7 +2,7 @@
  *  drivers/s390/char/tape_3590.c
  *    tape device discipline for 3590 tapes.
  *
- *    Copyright (C) IBM Corp. 2001,2006
+ *    Copyright IBM Corp. 2001,2006
  *    Author(s): Stefan Bader <shbader@de.ibm.com>
  *              Michael Holzheu <holzheu@de.ibm.com>
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
@@ -11,6 +11,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/bio.h>
+#include <asm/ebcdic.h>
 
 #define TAPE_DBF_AREA  tape_3590_dbf
 
@@ -30,7 +31,7 @@ EXPORT_SYMBOL(TAPE_DBF_AREA);
  * - Read Device (buffered) log: BRA
  * - Read Library log:          BRA
  * - Swap Devices:              BRA
- * - Long Busy:                         BRA
+ * - Long Busy:                         implemented
  * - Special Intercept:                 BRA
  * - Read Alternate:            implemented
  *******************************************************************/
@@ -94,6 +95,332 @@ static const char *tape_3590_msg[TAPE_3590_MAX_MSG] = {
        [0xae] = "Subsystem environmental alert",
 };
 
+static int crypt_supported(struct tape_device *device)
+{
+       return TAPE390_CRYPT_SUPPORTED(TAPE_3590_CRYPT_INFO(device));
+}
+
+static int crypt_enabled(struct tape_device *device)
+{
+       return TAPE390_CRYPT_ON(TAPE_3590_CRYPT_INFO(device));
+}
+
+static void ext_to_int_kekl(struct tape390_kekl *in,
+                           struct tape3592_kekl *out)
+{
+       int i;
+
+       memset(out, 0, sizeof(*out));
+       if (in->type == TAPE390_KEKL_TYPE_HASH)
+               out->flags |= 0x40;
+       if (in->type_on_tape == TAPE390_KEKL_TYPE_HASH)
+               out->flags |= 0x80;
+       strncpy(out->label, in->label, 64);
+       for (i = strlen(in->label); i < sizeof(out->label); i++)
+               out->label[i] = ' ';
+       ASCEBC(out->label, sizeof(out->label));
+}
+
+static void int_to_ext_kekl(struct tape3592_kekl *in,
+                           struct tape390_kekl *out)
+{
+       memset(out, 0, sizeof(*out));
+       if(in->flags & 0x40)
+               out->type = TAPE390_KEKL_TYPE_HASH;
+       else
+               out->type = TAPE390_KEKL_TYPE_LABEL;
+       if(in->flags & 0x80)
+               out->type_on_tape = TAPE390_KEKL_TYPE_HASH;
+       else
+               out->type_on_tape = TAPE390_KEKL_TYPE_LABEL;
+       memcpy(out->label, in->label, sizeof(in->label));
+       EBCASC(out->label, sizeof(in->label));
+       strstrip(out->label);
+}
+
+static void int_to_ext_kekl_pair(struct tape3592_kekl_pair *in,
+                                struct tape390_kekl_pair *out)
+{
+       if (in->count == 0) {
+               out->kekl[0].type = TAPE390_KEKL_TYPE_NONE;
+               out->kekl[0].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+               out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;
+               out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+       } else if (in->count == 1) {
+               int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);
+               out->kekl[1].type = TAPE390_KEKL_TYPE_NONE;
+               out->kekl[1].type_on_tape = TAPE390_KEKL_TYPE_NONE;
+       } else if (in->count == 2) {
+               int_to_ext_kekl(&in->kekl[0], &out->kekl[0]);
+               int_to_ext_kekl(&in->kekl[1], &out->kekl[1]);
+       } else {
+               printk("Invalid KEKL number: %d\n", in->count);
+               BUG();
+       }
+}
+
+static int check_ext_kekl(struct tape390_kekl *kekl)
+{
+       if (kekl->type == TAPE390_KEKL_TYPE_NONE)
+               goto invalid;
+       if (kekl->type > TAPE390_KEKL_TYPE_HASH)
+               goto invalid;
+       if (kekl->type_on_tape == TAPE390_KEKL_TYPE_NONE)
+               goto invalid;
+       if (kekl->type_on_tape > TAPE390_KEKL_TYPE_HASH)
+               goto invalid;
+       if ((kekl->type == TAPE390_KEKL_TYPE_HASH) &&
+           (kekl->type_on_tape == TAPE390_KEKL_TYPE_LABEL))
+               goto invalid;
+
+       return 0;
+invalid:
+       return -EINVAL;
+}
+
+static int check_ext_kekl_pair(struct tape390_kekl_pair *kekls)
+{
+       if (check_ext_kekl(&kekls->kekl[0]))
+               goto invalid;
+       if (check_ext_kekl(&kekls->kekl[1]))
+               goto invalid;
+
+       return 0;
+invalid:
+       return -EINVAL;
+}
+
+/*
+ * Query KEKLs
+ */
+static int tape_3592_kekl_query(struct tape_device *device,
+                               struct tape390_kekl_pair *ext_kekls)
+{
+       struct tape_request *request;
+       struct tape3592_kekl_query_order *order;
+       struct tape3592_kekl_query_data *int_kekls;
+       int rc;
+
+       DBF_EVENT(6, "tape3592_kekl_query\n");
+       int_kekls = kmalloc(sizeof(*int_kekls), GFP_KERNEL|GFP_DMA);
+       if (!int_kekls)
+               return -ENOMEM;
+       request = tape_alloc_request(2, sizeof(*order));
+       if (IS_ERR(request)) {
+               rc = PTR_ERR(request);
+               goto fail_malloc;
+       }
+       order = request->cpdata;
+       memset(order,0,sizeof(*order));
+       order->code = 0xe2;
+       order->max_count = 2;
+       request->op = TO_KEKL_QUERY;
+       tape_ccw_cc(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);
+       tape_ccw_end(request->cpaddr + 1, READ_SS_DATA, sizeof(*int_kekls),
+                    int_kekls);
+       rc = tape_do_io(device, request);
+       if (rc)
+               goto fail_request;
+       int_to_ext_kekl_pair(&int_kekls->kekls, ext_kekls);
+
+       rc = 0;
+fail_request:
+       tape_free_request(request);
+fail_malloc:
+       kfree(int_kekls);
+       return rc;
+}
+
+/*
+ * IOCTL: Query KEKLs
+ */
+static int tape_3592_ioctl_kekl_query(struct tape_device *device,
+                                     unsigned long arg)
+{
+       int rc;
+       struct tape390_kekl_pair *ext_kekls;
+
+       DBF_EVENT(6, "tape_3592_ioctl_kekl_query\n");
+       if (!crypt_supported(device))
+               return -ENOSYS;
+       if (!crypt_enabled(device))
+               return -EUNATCH;
+       ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL);
+       if (!ext_kekls)
+               return -ENOMEM;
+       rc = tape_3592_kekl_query(device, ext_kekls);
+       if (rc != 0)
+               goto fail;
+       if (copy_to_user((char __user *) arg, ext_kekls, sizeof(*ext_kekls))) {
+               rc = -EFAULT;
+               goto fail;
+       }
+       rc = 0;
+fail:
+       kfree(ext_kekls);
+       return rc;
+}
+
+static int tape_3590_mttell(struct tape_device *device, int mt_count);
+
+/*
+ * Set KEKLs
+ */
+static int tape_3592_kekl_set(struct tape_device *device,
+                             struct tape390_kekl_pair *ext_kekls)
+{
+       struct tape_request *request;
+       struct tape3592_kekl_set_order *order;
+
+       DBF_EVENT(6, "tape3592_kekl_set\n");
+       if (check_ext_kekl_pair(ext_kekls)) {
+               DBF_EVENT(6, "invalid kekls\n");
+               return -EINVAL;
+       }
+       if (tape_3590_mttell(device, 0) != 0)
+               return -EBADSLT;
+       request = tape_alloc_request(1, sizeof(*order));
+       if (IS_ERR(request))
+               return PTR_ERR(request);
+       order = request->cpdata;
+       memset(order, 0, sizeof(*order));
+       order->code = 0xe3;
+       order->kekls.count = 2;
+       ext_to_int_kekl(&ext_kekls->kekl[0], &order->kekls.kekl[0]);
+       ext_to_int_kekl(&ext_kekls->kekl[1], &order->kekls.kekl[1]);
+       request->op = TO_KEKL_SET;
+       tape_ccw_end(request->cpaddr, PERF_SUBSYS_FUNC, sizeof(*order), order);
+
+       return tape_do_io_free(device, request);
+}
+
+/*
+ * IOCTL: Set KEKLs
+ */
+static int tape_3592_ioctl_kekl_set(struct tape_device *device,
+                                   unsigned long arg)
+{
+       int rc;
+       struct tape390_kekl_pair *ext_kekls;
+
+       DBF_EVENT(6, "tape_3592_ioctl_kekl_set\n");
+       if (!crypt_supported(device))
+               return -ENOSYS;
+       if (!crypt_enabled(device))
+               return -EUNATCH;
+       ext_kekls = kmalloc(sizeof(*ext_kekls), GFP_KERNEL);
+       if (!ext_kekls)
+               return -ENOMEM;
+       if (copy_from_user(ext_kekls, (char __user *)arg, sizeof(*ext_kekls))) {
+               rc = -EFAULT;
+               goto out;
+       }
+       rc = tape_3592_kekl_set(device, ext_kekls);
+out:
+       kfree(ext_kekls);
+       return rc;
+}
+
+/*
+ * Enable encryption
+ */
+static int tape_3592_enable_crypt(struct tape_device *device)
+{
+       struct tape_request *request;
+       char *data;
+
+       DBF_EVENT(6, "tape_3592_enable_crypt\n");
+       if (!crypt_supported(device))
+               return -ENOSYS;
+       request = tape_alloc_request(2, 72);
+       if (IS_ERR(request))
+               return PTR_ERR(request);
+       data = request->cpdata;
+       memset(data,0,72);
+
+       data[0]       = 0x05;
+       data[36 + 0]  = 0x03;
+       data[36 + 1]  = 0x03;
+       data[36 + 4]  = 0x40;
+       data[36 + 6]  = 0x01;
+       data[36 + 14] = 0x2f;
+       data[36 + 18] = 0xc3;
+       data[36 + 35] = 0x72;
+       request->op = TO_CRYPT_ON;
+       tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
+       tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
+       return tape_do_io_free(device, request);
+}
+
+/*
+ * Disable encryption
+ */
+static int tape_3592_disable_crypt(struct tape_device *device)
+{
+       struct tape_request *request;
+       char *data;
+
+       DBF_EVENT(6, "tape_3592_disable_crypt\n");
+       if (!crypt_supported(device))
+               return -ENOSYS;
+       request = tape_alloc_request(2, 72);
+       if (IS_ERR(request))
+               return PTR_ERR(request);
+       data = request->cpdata;
+       memset(data,0,72);
+
+       data[0]       = 0x05;
+       data[36 + 0]  = 0x03;
+       data[36 + 1]  = 0x03;
+       data[36 + 35] = 0x32;
+
+       request->op = TO_CRYPT_OFF;
+       tape_ccw_cc(request->cpaddr, MODE_SET_CB, 36, data);
+       tape_ccw_end(request->cpaddr + 1, MODE_SET_CB, 36, data + 36);
+
+       return tape_do_io_free(device, request);
+}
+
+/*
+ * IOCTL: Set encryption status
+ */
+static int tape_3592_ioctl_crypt_set(struct tape_device *device,
+                                    unsigned long arg)
+{
+       struct tape390_crypt_info info;
+
+       DBF_EVENT(6, "tape_3592_ioctl_crypt_set\n");
+       if (!crypt_supported(device))
+               return -ENOSYS;
+       if (copy_from_user(&info, (char __user *)arg, sizeof(info)))
+               return -EFAULT;
+       if (info.status & ~TAPE390_CRYPT_ON_MASK)
+               return -EINVAL;
+       if (info.status & TAPE390_CRYPT_ON_MASK)
+               return tape_3592_enable_crypt(device);
+       else
+               return tape_3592_disable_crypt(device);
+}
+
+static int tape_3590_sense_medium(struct tape_device *device);
+
+/*
+ * IOCTL: Query enryption status
+ */
+static int tape_3592_ioctl_crypt_query(struct tape_device *device,
+                                      unsigned long arg)
+{
+       DBF_EVENT(6, "tape_3592_ioctl_crypt_query\n");
+       if (!crypt_supported(device))
+               return -ENOSYS;
+       tape_3590_sense_medium(device);
+       if (copy_to_user((char __user *) arg, &TAPE_3590_CRYPT_INFO(device),
+               sizeof(TAPE_3590_CRYPT_INFO(device))))
+               return -EFAULT;
+       else
+               return 0;
+}
+
 /*
  * 3590 IOCTL Overload
  */
@@ -109,6 +436,14 @@ tape_3590_ioctl(struct tape_device *device, unsigned int cmd, unsigned long arg)
 
                return tape_std_display(device, &disp);
        }
+       case TAPE390_KEKL_SET:
+               return tape_3592_ioctl_kekl_set(device, arg);
+       case TAPE390_KEKL_QUERY:
+               return tape_3592_ioctl_kekl_query(device, arg);
+       case TAPE390_CRYPT_SET:
+               return tape_3592_ioctl_crypt_set(device, arg);
+       case TAPE390_CRYPT_QUERY:
+               return tape_3592_ioctl_crypt_query(device, arg);
        default:
                return -EINVAL; /* no additional ioctls */
        }
@@ -248,6 +583,12 @@ tape_3590_work_handler(struct work_struct *work)
        case TO_READ_ATTMSG:
                tape_3590_read_attmsg(p->device);
                break;
+       case TO_CRYPT_ON:
+               tape_3592_enable_crypt(p->device);
+               break;
+       case TO_CRYPT_OFF:
+               tape_3592_disable_crypt(p->device);
+               break;
        default:
                DBF_EVENT(3, "T3590: work handler undefined for "
                          "operation 0x%02x\n", p->op);
@@ -365,6 +706,33 @@ tape_3590_check_locate(struct tape_device *device, struct tape_request *request)
 }
 #endif
 
+static void tape_3590_med_state_set(struct tape_device *device,
+                                   struct tape_3590_med_sense *sense)
+{
+       struct tape390_crypt_info *c_info;
+
+       c_info = &TAPE_3590_CRYPT_INFO(device);
+
+       if (sense->masst == MSENSE_UNASSOCIATED) {
+               tape_med_state_set(device, MS_UNLOADED);
+               TAPE_3590_CRYPT_INFO(device).medium_status = 0;
+               return;
+       }
+       if (sense->masst != MSENSE_ASSOCIATED_MOUNT) {
+               PRINT_ERR("Unknown medium state: %x\n", sense->masst);
+               return;
+       }
+       tape_med_state_set(device, MS_LOADED);
+       c_info->medium_status |= TAPE390_MEDIUM_LOADED_MASK;
+       if (sense->flags & MSENSE_CRYPT_MASK) {
+               PRINT_INFO("Medium is encrypted (%04x)\n", sense->flags);
+               c_info->medium_status |= TAPE390_MEDIUM_ENCRYPTED_MASK;
+       } else  {
+               DBF_EVENT(6, "Medium is not encrypted %04x\n", sense->flags);
+               c_info->medium_status &= ~TAPE390_MEDIUM_ENCRYPTED_MASK;
+       }
+}
+
 /*
  * The done handler is called at device/channel end and wakes up the sleeping
  * process
@@ -372,9 +740,10 @@ tape_3590_check_locate(struct tape_device *device, struct tape_request *request)
 static int
 tape_3590_done(struct tape_device *device, struct tape_request *request)
 {
-       struct tape_3590_med_sense *sense;
+       struct tape_3590_disc_data *disc_data;
 
        DBF_EVENT(6, "%s done\n", tape_op_verbose[request->op]);
+       disc_data = device->discdata;
 
        switch (request->op) {
        case TO_BSB:
@@ -394,13 +763,20 @@ tape_3590_done(struct tape_device *device, struct tape_request *request)
                break;
        case TO_RUN:
                tape_med_state_set(device, MS_UNLOADED);
+               tape_3590_schedule_work(device, TO_CRYPT_OFF);
                break;
        case TO_MSEN:
-               sense = (struct tape_3590_med_sense *) request->cpdata;
-               if (sense->masst == MSENSE_UNASSOCIATED)
-                       tape_med_state_set(device, MS_UNLOADED);
-               if (sense->masst == MSENSE_ASSOCIATED_MOUNT)
-                       tape_med_state_set(device, MS_LOADED);
+               tape_3590_med_state_set(device, request->cpdata);
+               break;
+       case TO_CRYPT_ON:
+               TAPE_3590_CRYPT_INFO(device).status
+                       |= TAPE390_CRYPT_ON_MASK;
+               *(device->modeset_byte) |= 0x03;
+               break;
+       case TO_CRYPT_OFF:
+               TAPE_3590_CRYPT_INFO(device).status
+                       &= ~TAPE390_CRYPT_ON_MASK;
+               *(device->modeset_byte) &= ~0x03;
                break;
        case TO_RBI:    /* RBI seems to succeed even without medium loaded. */
        case TO_NOP:    /* Same to NOP. */
@@ -409,8 +785,9 @@ tape_3590_done(struct tape_device *device, struct tape_request *request)
        case TO_DIS:
        case TO_ASSIGN:
        case TO_UNASSIGN:
-               break;
        case TO_SIZE:
+       case TO_KEKL_SET:
+       case TO_KEKL_QUERY:
                break;
        }
        return TAPE_IO_SUCCESS;
@@ -540,10 +917,8 @@ static int
 tape_3590_erp_long_busy(struct tape_device *device,
                        struct tape_request *request, struct irb *irb)
 {
-       /* FIXME: how about WAITING for a minute ? */
-       PRINT_WARN("(%s): Device is busy! Please wait a minute!\n",
-                  device->cdev->dev.bus_id);
-       return tape_3590_erp_basic(device, request, irb, -EBUSY);
+       DBF_EVENT(6, "Device is busy\n");
+       return TAPE_IO_LONG_BUSY;
 }
 
 /*
@@ -951,6 +1326,34 @@ tape_3590_print_era_msg(struct tape_device *device, struct irb *irb)
                   device->cdev->dev.bus_id, sense->mc);
 }
 
+static int tape_3590_crypt_error(struct tape_device *device,
+                                struct tape_request *request, struct irb *irb)
+{
+       u8 cu_rc, ekm_rc1;
+       u16 ekm_rc2;
+       u32 drv_rc;
+       char *bus_id, *sense;
+
+       sense = ((struct tape_3590_sense *) irb->ecw)->fmt.data;
+       bus_id = device->cdev->dev.bus_id;
+       cu_rc = sense[0];
+       drv_rc = *((u32*) &sense[5]) & 0xffffff;
+       ekm_rc1 = sense[9];
+       ekm_rc2 = *((u16*) &sense[10]);
+       if ((cu_rc == 0) && (ekm_rc2 == 0xee31))
+               /* key not defined on EKM */
+               return tape_3590_erp_basic(device, request, irb, -EKEYREJECTED);
+       if ((cu_rc == 1) || (cu_rc == 2))
+               /* No connection to EKM */
+               return tape_3590_erp_basic(device, request, irb, -ENOTCONN);
+
+       PRINT_ERR("(%s): Unable to get encryption key from EKM\n", bus_id);
+       PRINT_ERR("(%s): CU=%02X DRIVE=%06X EKM=%02X:%04X\n", bus_id, cu_rc,
+               drv_rc, ekm_rc1, ekm_rc2);
+
+       return tape_3590_erp_basic(device, request, irb, -ENOKEY);
+}
+
 /*
  *  3590 error Recovery routine:
  *  If possible, it tries to recover from the error. If this is not possible,
@@ -979,6 +1382,8 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
 
        sense = (struct tape_3590_sense *) irb->ecw;
 
+       DBF_EVENT(6, "Unit Check: RQC = %x\n", sense->rc_rqc);
+
        /*
         * First check all RC-QRCs where we want to do something special
         *   - "break":     basic error recovery is done
@@ -999,6 +1404,8 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
        case 0x2231:
                tape_3590_print_era_msg(device, irb);
                return tape_3590_erp_special_interrupt(device, request, irb);
+       case 0x2240:
+               return tape_3590_crypt_error(device, request, irb);
 
        case 0x3010:
                DBF_EVENT(2, "(%08x): Backward at Beginning of Partition\n",
@@ -1020,6 +1427,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
                DBF_EVENT(2, "(%08x): Rewind Unload complete\n",
                          device->cdev_id);
                tape_med_state_set(device, MS_UNLOADED);
+               tape_3590_schedule_work(device, TO_CRYPT_OFF);
                return tape_3590_erp_basic(device, request, irb, 0);
 
        case 0x4010:
@@ -1030,9 +1438,15 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
                PRINT_WARN("(%s): Tape operation when medium not loaded\n",
                           device->cdev->dev.bus_id);
                tape_med_state_set(device, MS_UNLOADED);
+               tape_3590_schedule_work(device, TO_CRYPT_OFF);
                return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
        case 0x4012:            /* Device Long Busy */
+               /* XXX: Also use long busy handling here? */
+               DBF_EVENT(6, "(%08x): LONG BUSY\n", device->cdev_id);
                tape_3590_print_era_msg(device, irb);
+               return tape_3590_erp_basic(device, request, irb, -EBUSY);
+       case 0x4014:
+               DBF_EVENT(6, "(%08x): Crypto LONG BUSY\n", device->cdev_id);
                return tape_3590_erp_long_busy(device, request, irb);
 
        case 0x5010:
@@ -1064,6 +1478,7 @@ tape_3590_unit_check(struct tape_device *device, struct tape_request *request,
        case 0x5120:
        case 0x1120:
                tape_med_state_set(device, MS_UNLOADED);
+               tape_3590_schedule_work(device, TO_CRYPT_OFF);
                return tape_3590_erp_basic(device, request, irb, -ENOMEDIUM);
 
        case 0x6020:
@@ -1142,21 +1557,47 @@ tape_3590_setup_device(struct tape_device *device)
 {
        int rc;
        struct tape_3590_disc_data *data;
+       char *rdc_data;
 
        DBF_EVENT(6, "3590 device setup\n");
-       data = kmalloc(sizeof(struct tape_3590_disc_data),
-                      GFP_KERNEL | GFP_DMA);
+       data = kzalloc(sizeof(struct tape_3590_disc_data), GFP_KERNEL | GFP_DMA);
        if (data == NULL)
                return -ENOMEM;
        data->read_back_op = READ_PREVIOUS;
        device->discdata = data;
 
-       if ((rc = tape_std_assign(device)) == 0) {
-               /* Try to find out if medium is loaded */
-               if ((rc = tape_3590_sense_medium(device)) != 0)
-                       DBF_LH(3, "3590 medium sense returned %d\n", rc);
+       rdc_data = kmalloc(64, GFP_KERNEL | GFP_DMA);
+       if (!rdc_data) {
+               rc = -ENOMEM;
+               goto fail_kmalloc;
+       }
+       rc = read_dev_chars(device->cdev, (void**)&rdc_data, 64);
+       if (rc) {
+               DBF_LH(3, "Read device characteristics failed!\n");
+               goto fail_kmalloc;
+       }
+       rc = tape_std_assign(device);
+       if (rc)
+               goto fail_rdc_data;
+       if (rdc_data[31] == 0x13) {
+               PRINT_INFO("Device has crypto support\n");
+               data->crypt_info.capability |= TAPE390_CRYPT_SUPPORTED_MASK;
+               tape_3592_disable_crypt(device);
+       } else {
+               DBF_EVENT(6, "Device has NO crypto support\n");
        }
+       /* Try to find out if medium is loaded */
+       rc = tape_3590_sense_medium(device);
+       if (rc) {
+               DBF_LH(3, "3590 medium sense returned %d\n", rc);
+               goto fail_rdc_data;
+       }
+       return 0;
 
+fail_rdc_data:
+       kfree(rdc_data);
+fail_kmalloc:
+       kfree(data);
        return rc;
 }
 
index cf274b9..aa51388 100644 (file)
@@ -2,7 +2,7 @@
  *  drivers/s390/char/tape_3590.h
  *    tape device discipline for 3590 tapes.
  *
- *    Copyright (C) IBM Corp. 2001,2006
+ *    Copyright IBM Corp. 2001,2006
  *    Author(s): Stefan Bader <shbader@de.ibm.com>
  *              Michael Holzheu <holzheu@de.ibm.com>
  *              Martin Schwidefsky <schwidefsky@de.ibm.com>
 #define MSENSE_UNASSOCIATED     0x00
 #define MSENSE_ASSOCIATED_MOUNT         0x01
 #define MSENSE_ASSOCIATED_UMOUNT 0x02
+#define MSENSE_CRYPT_MASK       0x00000010
 
 #define TAPE_3590_MAX_MSG       0xb0
 
 /* Datatypes */
 
 struct tape_3590_disc_data {
-       unsigned char modeset_byte;
+       struct tape390_crypt_info crypt_info;
        int read_back_op;
 };
 
+#define TAPE_3590_CRYPT_INFO(device) \
+       ((struct tape_3590_disc_data*)(device->discdata))->crypt_info
+#define TAPE_3590_READ_BACK_OP(device) \
+       ((struct tape_3590_disc_data*)(device->discdata))->read_back_op
+
 struct tape_3590_sense {
 
        unsigned int command_rej:1;
@@ -118,7 +124,48 @@ struct tape_3590_sense {
 struct tape_3590_med_sense {
        unsigned int macst:4;
        unsigned int masst:4;
-       char pad[127];
+       char pad1[7];
+       unsigned int flags;
+       char pad2[116];
+} __attribute__ ((packed));
+
+/* Datastructures for 3592 encryption support */
+
+struct tape3592_kekl {
+       __u8 flags;
+       char label[64];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_pair {
+       __u8 count;
+       struct tape3592_kekl kekl[2];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_query_data {
+       __u16 len;
+       __u8  fmt;
+       __u8  mc;
+       __u32 id;
+       __u8  flags;
+       struct tape3592_kekl_pair kekls;
+       char reserved[116];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_query_order {
+       __u8 code;
+       __u8 flags;
+       char reserved1[2];
+       __u8 max_count;
+       char reserved2[35];
+} __attribute__ ((packed));
+
+struct tape3592_kekl_set_order {
+       __u8 code;
+       __u8 flags;
+       char reserved1[2];
+       __u8 op;
+       struct tape3592_kekl_pair kekls;
+       char reserved2[120];
 } __attribute__ ((packed));
 
 #endif /* _TAPE_3590_H */
index c8a89b3..dd0ecae 100644 (file)
@@ -73,7 +73,7 @@ tapeblock_trigger_requeue(struct tape_device *device)
 /*
  * Post finished request.
  */
-static inline void
+static void
 tapeblock_end_request(struct request *req, int uptodate)
 {
        if (end_that_request_first(req, uptodate, req->hard_nr_sectors))
@@ -108,7 +108,7 @@ __tapeblock_end_request(struct tape_request *ccw_req, void *data)
 /*
  * Feed the tape device CCW queue with requests supplied in a list.
  */
-static inline int
+static int
 tapeblock_start_request(struct tape_device *device, struct request *req)
 {
        struct tape_request *   ccw_req;
index 31198c8..9faea04 100644 (file)
@@ -3,7 +3,7 @@
  *    character device frontend for tape device driver
  *
  *  S390 and zSeries version
- *    Copyright (C) 2001,2002 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 2001,2006
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *              Michael Holzheu <holzheu@de.ibm.com>
  *              Tuan Ngo-Anh <ngoanh@de.ibm.com>
@@ -89,22 +89,7 @@ tapechar_cleanup_device(struct tape_device *device)
        device->nt = NULL;
 }
 
-/*
- * Terminate write command (we write two TMs and skip backward over last)
- * This ensures that the tape is always correctly terminated.
- * When the user writes afterwards a new file, he will overwrite the
- * second TM and therefore one TM will remain to separate the
- * two files on the tape...
- */
-static inline void
-tapechar_terminate_write(struct tape_device *device)
-{
-       if (tape_mtop(device, MTWEOF, 1) == 0 &&
-           tape_mtop(device, MTWEOF, 1) == 0)
-               tape_mtop(device, MTBSR, 1);
-}
-
-static inline int
+static int
 tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
 {
        struct idal_buffer *new;
@@ -137,7 +122,7 @@ tapechar_check_idalbuffer(struct tape_device *device, size_t block_size)
 /*
  * Tape device read function
  */
-ssize_t
+static ssize_t
 tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
 {
        struct tape_device *device;
@@ -201,7 +186,7 @@ tapechar_read(struct file *filp, char __user *data, size_t count, loff_t *ppos)
 /*
  * Tape device write function
  */
-ssize_t
+static ssize_t
 tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t *ppos)
 {
        struct tape_device *device;
@@ -291,7 +276,7 @@ tapechar_write(struct file *filp, const char __user *data, size_t count, loff_t
 /*
  * Character frontend tape device open function.
  */
-int
+static int
 tapechar_open (struct inode *inode, struct file *filp)
 {
        struct tape_device *device;
@@ -326,7 +311,7 @@ tapechar_open (struct inode *inode, struct file *filp)
  * Character frontend tape device release function.
  */
 
-int
+static int
 tapechar_release(struct inode *inode, struct file *filp)
 {
        struct tape_device *device;
index c6c2e91..e2a8a1a 100644 (file)
@@ -3,7 +3,7 @@
  *    basic function of the tape device driver
  *
  *  S390 and zSeries version
- *    Copyright (C) 2001,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ *    Copyright IBM Corp. 2001,2006
  *    Author(s): Carsten Otte <cotte@de.ibm.com>
  *              Michael Holzheu <holzheu@de.ibm.com>
  *              Tuan Ngo-Anh <ngoanh@de.ibm.com>
 #include "tape_std.h"
 
 #define PRINTK_HEADER "TAPE_CORE: "
+#define LONG_BUSY_TIMEOUT 180 /* seconds */
 
 static void __tape_do_irq (struct ccw_device *, unsigned long, struct irb *);
 static void tape_delayed_next_request(struct work_struct *);
+static void tape_long_busy_timeout(unsigned long data);
 
 /*
  * One list to contain all tape devices of all disciplines, so
@@ -69,10 +71,12 @@ const char *tape_op_verbose[TO_SIZE] =
        [TO_LOAD] = "LOA",      [TO_READ_CONFIG] = "RCF",
        [TO_READ_ATTMSG] = "RAT",
        [TO_DIS] = "DIS",       [TO_ASSIGN] = "ASS",
-       [TO_UNASSIGN] = "UAS"
+       [TO_UNASSIGN] = "UAS",  [TO_CRYPT_ON] = "CON",
+       [TO_CRYPT_OFF] = "COF", [TO_KEKL_SET] = "KLS",
+       [TO_KEKL_QUERY] = "KLQ",
 };
 
-static inline int
+static int
 busid_to_int(char *bus_id)
 {
        int     dec;
@@ -252,7 +256,7 @@ tape_med_state_set(struct tape_device *device, enum tape_medium_state newstate)
 /*
  * Stop running ccw. Has to be called with the device lock held.
  */
-static inline int
+static int
 __tape_cancel_io(struct tape_device *device, struct tape_request *request)
 {
        int retries;
@@ -346,6 +350,9 @@ tape_generic_online(struct tape_device *device,
                return -EINVAL;
        }
 
+       init_timer(&device->lb_timeout);
+       device->lb_timeout.function = tape_long_busy_timeout;
+
        /* Let the discipline have a go at the device. */
        device->discipline = discipline;
        if (!try_module_get(discipline->owner)) {
@@ -385,7 +392,7 @@ out:
        return rc;
 }
 
-static inline void
+static void
 tape_cleanup_device(struct tape_device *device)
 {
        tapeblock_cleanup_device(device);
@@ -563,7 +570,7 @@ tape_generic_probe(struct ccw_device *cdev)
        return ret;
 }
 
-static inline void
+static void
 __tape_discard_requests(struct tape_device *device)
 {
        struct tape_request *   request;
@@ -703,7 +710,7 @@ tape_free_request (struct tape_request * request)
        kfree(request);
 }
 
-static inline int
+static int
 __tape_start_io(struct tape_device *device, struct tape_request *request)
 {
        int rc;
@@ -733,7 +740,7 @@ __tape_start_io(struct tape_device *device, struct tape_request *request)
        return rc;
 }
 
-static inline void
+static void
 __tape_start_next_request(struct tape_device *device)
 {
        struct list_head *l, *n;
@@ -801,7 +808,23 @@ tape_delayed_next_request(struct work_struct *work)
        spin_unlock_irq(get_ccwdev_lock(device->cdev));
 }
 
-static inline void
+static void tape_long_busy_timeout(unsigned long data)
+{
+       struct tape_request *request;
+       struct tape_device *device;
+
+       device = (struct tape_device *) data;
+       spin_lock_irq(get_ccwdev_lock(device->cdev));
+       request = list_entry(device->req_queue.next, struct tape_request, list);
+       if (request->status != TAPE_REQUEST_LONG_BUSY)
+               BUG();
+       DBF_LH(6, "%08x: Long busy timeout.\n", device->cdev_id);
+       __tape_start_next_request(device);
+       device->lb_timeout.data = (unsigned long) tape_put_device(device);
+       spin_unlock_irq(get_ccwdev_lock(device->cdev));
+}
+
+static void
 __tape_end_request(
        struct tape_device *    device,
        struct tape_request *   request,
@@ -878,7 +901,7 @@ tape_dump_sense_dbf(struct tape_device *device, struct tape_request *request,
  * and starts it if the tape is idle. Has to be called with
  * the device lock held.
  */
-static inline int
+static int
 __tape_start_request(struct tape_device *device, struct tape_request *request)
 {
        int rc;
@@ -1094,7 +1117,22 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
        /* May be an unsolicited irq */
        if(request != NULL)
                request->rescnt = irb->scsw.count;
-
+       else if ((irb->scsw.dstat == 0x85 || irb->scsw.dstat == 0x80) &&
+                !list_empty(&device->req_queue)) {
+               /* Not Ready to Ready after long busy ? */
+               struct tape_request *req;
+               req = list_entry(device->req_queue.next,
+                                struct tape_request, list);
+               if (req->status == TAPE_REQUEST_LONG_BUSY) {
+                       DBF_EVENT(3, "(%08x): del timer\n", device->cdev_id);
+                       if (del_timer(&device->lb_timeout)) {
+                               device->lb_timeout.data = (unsigned long)
+                                       tape_put_device(device);
+                               __tape_start_next_request(device);
+                       }
+                       return;
+               }
+       }
        if (irb->scsw.dstat != 0x0c) {
                /* Set the 'ONLINE' flag depending on sense byte 1 */
                if(*(((__u8 *) irb->ecw) + 1) & SENSE_DRIVE_ONLINE)
@@ -1142,6 +1180,15 @@ __tape_do_irq (struct ccw_device *cdev, unsigned long intparm, struct irb *irb)
                        break;
                case TAPE_IO_PENDING:
                        break;
+               case TAPE_IO_LONG_BUSY:
+                       device->lb_timeout.data =
+                               (unsigned long)tape_get_device_reference(device);
+                       device->lb_timeout.expires = jiffies +
+                               LONG_BUSY_TIMEOUT * HZ;
+                       DBF_EVENT(3, "(%08x): add timer\n", device->cdev_id);
+                       add_timer(&device->lb_timeout);
+                       request->status = TAPE_REQUEST_LONG_BUSY;
+                       break;
                case TAPE_IO_RETRY:
                        rc = __tape_start_io(device, request);
                        if (rc)
index 0984462..bc33068 100644 (file)
@@ -36,7 +36,7 @@
 struct tty_driver *tty3270_driver;
 static int tty3270_max_index;
 
-struct raw3270_fn tty3270_fn;
+static struct raw3270_fn tty3270_fn;
 
 struct tty3270_cell {
        unsigned char character;
@@ -119,8 +119,7 @@ static void tty3270_update(struct tty3270 *);
 /*
  * Setup timeout for a device. On timeout trigger an update.
  */
-void
-tty3270_set_timer(struct tty3270 *tp, int expires)
+static void tty3270_set_timer(struct tty3270 *tp, int expires)
 {
        if (expires == 0) {
                if (timer_pending(&tp->timer) && del_timer(&tp->timer))
@@ -841,7 +840,7 @@ tty3270_del_views(void)
        }
 }
 
-struct raw3270_fn tty3270_fn = {
+static struct raw3270_fn tty3270_fn = {
        .activate = tty3270_activate,
        .deactivate = tty3270_deactivate,
        .intv = (void *) tty3270_irq,
@@ -1754,8 +1753,7 @@ static const struct tty_operations tty3270_ops = {
        .set_termios = tty3270_set_termios
 };
 
-void
-tty3270_notifier(int index, int active)
+static void tty3270_notifier(int index, int active)
 {
        if (active)
                tty_register_device(tty3270_driver, index, NULL);
@@ -1767,8 +1765,7 @@ tty3270_notifier(int index, int active)
  * 3270 tty registration code called from tty_init().
  * Most kernel services (incl. kmalloc) are available at this poimt.
  */
-int __init
-tty3270_init(void)
+static int __init tty3270_init(void)
 {
        struct tty_driver *driver;
        int ret;
index 6cb2304..4f894dc 100644 (file)
@@ -128,9 +128,8 @@ static iucv_interrupt_ops_t vmlogrdr_iucvops = {
        .MessagePending     = vmlogrdr_iucv_MessagePending,
 };
 
-
-DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue);
-DECLARE_WAIT_QUEUE_HEAD(read_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue);
+static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue);
 
 /*
  * pointer to system service private structure
index 12c2d6b..aa65df4 100644 (file)
@@ -43,7 +43,7 @@ typedef enum {add, free} range_action;
  * Function: blacklist_range
  * (Un-)blacklist the devices from-to
  */
-static inline void
+static void
 blacklist_range (range_action action, unsigned int from, unsigned int to,
                 unsigned int ssid)
 {
@@ -69,7 +69,7 @@ blacklist_range (range_action action, unsigned int from, unsigned int to,
  * Get devno/busid from given string.
  * Shamelessly grabbed from dasd_devmap.c.
  */
-static inline int
+static int
 blacklist_busid(char **str, int *id0, int *ssid, int *devno)
 {
        int val, old_style;
@@ -123,10 +123,10 @@ confused:
        return 1;
 }
 
-static inline int
+static int
 blacklist_parse_parameters (char *str, range_action action)
 {
-       unsigned int from, to, from_id0, to_id0, from_ssid, to_ssid;
+       int from, to, from_id0, to_id0, from_ssid, to_ssid;
 
        while (*str != 0 && *str != '\n') {
                range_action ra = action;
@@ -227,7 +227,7 @@ is_blacklisted (int ssid, int devno)
  * Function: blacklist_parse_proc_parameters
  * parse the stuff which is piped to /proc/cio_ignore
  */
-static inline void
+static void
 blacklist_parse_proc_parameters (char *buf)
 {
        if (strncmp (buf, "free ", 5) == 0) {
index 38954f5..d48e3ca 100644 (file)
@@ -53,7 +53,7 @@ ccwgroup_uevent (struct device *dev, char **envp, int num_envp, char *buffer,
 
 static struct bus_type ccwgroup_bus_type;
 
-static inline void
+static void
 __ccwgroup_remove_symlinks(struct ccwgroup_device *gdev)
 {
        int i;
@@ -104,7 +104,7 @@ ccwgroup_release (struct device *dev)
        kfree(gdev);
 }
 
-static inline int
+static int
 __ccwgroup_create_symlinks(struct ccwgroup_device *gdev)
 {
        char str[8];
@@ -424,7 +424,7 @@ ccwgroup_probe_ccwdev(struct ccw_device *cdev)
        return 0;
 }
 
-static inline struct ccwgroup_device *
+static struct ccwgroup_device *
 __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
 {
        struct ccwgroup_device *gdev;
index cbab8d2..6f05a44 100644 (file)
@@ -93,7 +93,7 @@ chsc_get_sch_desc_irq(struct subchannel *sch, void *page)
                u16 sch;          /* subchannel */
                u8 chpid[8];      /* chpids 0-7 */
                u16 fla[8];       /* full link addresses 0-7 */
-       } *ssd_area;
+       } __attribute__ ((packed)) *ssd_area;
 
        ssd_area = page;
 
@@ -277,7 +277,7 @@ out_unreg:
        return 0;
 }
 
-static inline void
+static void
 s390_set_chpid_offline( __u8 chpid)
 {
        char dbf_txt[15];
@@ -338,7 +338,7 @@ s390_process_res_acc_sch(struct res_acc_data *res_data, struct subchannel *sch)
        return 0x80 >> chp;
 }
 
-static inline int
+static int
 s390_process_res_acc_new_sch(struct subchannel_id schid)
 {
        struct schib schib;
@@ -444,7 +444,7 @@ __get_chpid_from_lir(void *data)
                u32 andesc[28];
                /* incident-specific information */
                u32 isinfo[28];
-       } *lir;
+       } __attribute__ ((packed)) *lir;
 
        lir = data;
        if (!(lir->iq&0x80))
@@ -461,154 +461,146 @@ __get_chpid_from_lir(void *data)
        return (u16) (lir->indesc[0]&0x000000ff);
 }
 
-int
-chsc_process_crw(void)
+struct chsc_sei_area {
+       struct chsc_header request;
+       u32 reserved1;
+       u32 reserved2;
+       u32 reserved3;
+       struct chsc_header response;
+       u32 reserved4;
+       u8  flags;
+       u8  vf;         /* validity flags */
+       u8  rs;         /* reporting source */
+       u8  cc;         /* content code */
+       u16 fla;        /* full link address */
+       u16 rsid;       /* reporting source id */
+       u32 reserved5;
+       u32 reserved6;
+       u8 ccdf[4096 - 16 - 24];        /* content-code dependent field */
+       /* ccdf has to be big enough for a link-incident record */
+} __attribute__ ((packed));
+
+static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
+{
+       int chpid;
+
+       CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n",
+                     sei_area->rs, sei_area->rsid);
+       if (sei_area->rs != 4)
+               return 0;
+       chpid = __get_chpid_from_lir(sei_area->ccdf);
+       if (chpid < 0)
+               CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n");
+       else
+               s390_set_chpid_offline(chpid);
+
+       return 0;
+}
+
+static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
 {
-       int chpid, ret;
        struct res_acc_data res_data;
-       struct {
-               struct chsc_header request;
-               u32 reserved1;
-               u32 reserved2;
-               u32 reserved3;
-               struct chsc_header response;
-               u32 reserved4;
-               u8  flags;
-               u8  vf;         /* validity flags */
-               u8  rs;         /* reporting source */
-               u8  cc;         /* content code */
-               u16 fla;        /* full link address */
-               u16 rsid;       /* reporting source id */
-               u32 reserved5;
-               u32 reserved6;
-               u32 ccdf[96];   /* content-code dependent field */
-               /* ccdf has to be big enough for a link-incident record */
-       } *sei_area;
+       struct device *dev;
+       int status;
+       int rc;
+
+       CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, "
+                     "rs_id=%04x)\n", sei_area->rs, sei_area->rsid);
+       if (sei_area->rs != 4)
+               return 0;
+       /* allocate a new channel path structure, if needed */
+       status = get_chp_status(sei_area->rsid);
+       if (status < 0)
+               new_channel_path(sei_area->rsid);
+       else if (!status)
+               return 0;
+       dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
+       memset(&res_data, 0, sizeof(struct res_acc_data));
+       res_data.chp = to_channelpath(dev);
+       if ((sei_area->vf & 0xc0) != 0) {
+               res_data.fla = sei_area->fla;
+               if ((sei_area->vf & 0xc0) == 0xc0)
+                       /* full link address */
+                       res_data.fla_mask = 0xffff;
+               else
+                       /* link address */
+                       res_data.fla_mask = 0xff00;
+       }
+       rc = s390_process_res_acc(&res_data);
+       put_device(dev);
+
+       return rc;
+}
+
+static int chsc_process_sei(struct chsc_sei_area *sei_area)
+{
+       int rc;
+
+       /* Check if we might have lost some information. */
+       if (sei_area->flags & 0x40)
+               CIO_CRW_EVENT(2, "chsc: event overflow\n");
+       /* which kind of information was stored? */
+       rc = 0;
+       switch (sei_area->cc) {
+       case 1: /* link incident*/
+               rc = chsc_process_sei_link_incident(sei_area);
+               break;
+       case 2: /* i/o resource accessibiliy */
+               rc = chsc_process_sei_res_acc(sei_area);
+               break;
+       default: /* other stuff */
+               CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n",
+                             sei_area->cc);
+               break;
+       }
+
+       return rc;
+}
+
+int chsc_process_crw(void)
+{
+       struct chsc_sei_area *sei_area;
+       int ret;
+       int rc;
 
        if (!sei_page)
                return 0;
-       /*
-        * build the chsc request block for store event information
-        * and do the call
-        * This function is only called by the machine check handler thread,
-        * so we don't need locking for the sei_page.
-        */
+       /* Access to sei_page is serialized through machine check handler
+        * thread, so no need for locking. */
        sei_area = sei_page;
 
        CIO_TRACE_EVENT( 2, "prcss");
        ret = 0;
        do {
-               int ccode, status;
-               struct device *dev;
                memset(sei_area, 0, sizeof(*sei_area));
-               memset(&res_data, 0, sizeof(struct res_acc_data));
                sei_area->request.length = 0x0010;
                sei_area->request.code = 0x000e;
+               if (chsc(sei_area))
+                       break;
 
-               ccode = chsc(sei_area);
-               if (ccode > 0)
-                       return 0;
-
-               switch (sei_area->response.code) {
-                       /* for debug purposes, check for problems */
-               case 0x0001:
-                       CIO_CRW_EVENT(4, "chsc_process_crw: event information "
-                                       "successfully stored\n");
-                       break; /* everything ok */
-               case 0x0002:
-                       CIO_CRW_EVENT(2,
-                                     "chsc_process_crw: invalid command!\n");
-                       return 0;
-               case 0x0003:
-                       CIO_CRW_EVENT(2, "chsc_process_crw: error in chsc "
-                                     "request block!\n");
-                       return 0;
-               case 0x0005:
-                       CIO_CRW_EVENT(2, "chsc_process_crw: no event "
-                                     "information stored\n");
-                       return 0;
-               default:
-                       CIO_CRW_EVENT(2, "chsc_process_crw: chsc response %d\n",
+               if (sei_area->response.code == 0x0001) {
+                       CIO_CRW_EVENT(4, "chsc: sei successful\n");
+                       rc = chsc_process_sei(sei_area);
+                       if (rc)
+                               ret = rc;
+               } else {
+                       CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
                                      sei_area->response.code);
-                       return 0;
-               }
-
-               /* Check if we might have lost some information. */
-               if (sei_area->flags & 0x40)
-                       CIO_CRW_EVENT(2, "chsc_process_crw: Event information "
-                                      "has been lost due to overflow!\n");
-
-               if (sei_area->rs != 4) {
-                       CIO_CRW_EVENT(2, "chsc_process_crw: reporting source "
-                                     "(%04X) isn't a chpid!\n",
-                                     sei_area->rsid);
-                       continue;
-               }
-
-               /* which kind of information was stored? */
-               switch (sei_area->cc) {
-               case 1: /* link incident*/
-                       CIO_CRW_EVENT(4, "chsc_process_crw: "
-                                     "channel subsystem reports link incident,"
-                                     " reporting source is chpid %x\n",
-                                     sei_area->rsid);
-                       chpid = __get_chpid_from_lir(sei_area->ccdf);
-                       if (chpid < 0)
-                               CIO_CRW_EVENT(4, "%s: Invalid LIR, skipping\n",
-                                             __FUNCTION__);
-                       else
-                               s390_set_chpid_offline(chpid);
-                       break;
-                       
-               case 2: /* i/o resource accessibiliy */
-                       CIO_CRW_EVENT(4, "chsc_process_crw: "
-                                     "channel subsystem reports some I/O "
-                                     "devices may have become accessible\n");
-                       pr_debug("Data received after sei: \n");
-                       pr_debug("Validity flags: %x\n", sei_area->vf);
-                       
-                       /* allocate a new channel path structure, if needed */
-                       status = get_chp_status(sei_area->rsid);
-                       if (status < 0)
-                               new_channel_path(sei_area->rsid);
-                       else if (!status)
-                               break;
-                       dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
-                       res_data.chp = to_channelpath(dev);
-                       pr_debug("chpid: %x", sei_area->rsid);
-                       if ((sei_area->vf & 0xc0) != 0) {
-                               res_data.fla = sei_area->fla;
-                               if ((sei_area->vf & 0xc0) == 0xc0) {
-                                       pr_debug(" full link addr: %x",
-                                                sei_area->fla);
-                                       res_data.fla_mask = 0xffff;
-                               } else {
-                                       pr_debug(" link addr: %x",
-                                                sei_area->fla);
-                                       res_data.fla_mask = 0xff00;
-                               }
-                       }
-                       ret = s390_process_res_acc(&res_data);
-                       pr_debug("\n\n");
-                       put_device(dev);
-                       break;
-                       
-               default: /* other stuff */
-                       CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n",
-                                     sei_area->cc);
+                       ret = 0;
                        break;
                }
        } while (sei_area->flags & 0x80);
+
        return ret;
 }
 
-static inline int
+static int
 __chp_add_new_sch(struct subchannel_id schid)
 {
        struct schib schib;
        int ret;
 
-       if (stsch(schid, &schib))
+       if (stsch_err(schid, &schib))
                /* We're through */
                return need_rescan ? -EAGAIN : -ENXIO;
 
@@ -709,7 +701,7 @@ chp_process_crw(int chpid, int on)
        return chp_add(chpid);
 }
 
-static inline int check_for_io_on_path(struct subchannel *sch, int index)
+static int check_for_io_on_path(struct subchannel *sch, int index)
 {
        int cc;
 
@@ -741,7 +733,7 @@ static void terminate_internal_io(struct subchannel *sch)
                sch->driver->termination(&sch->dev);
 }
 
-static inline void
+static void
 __s390_subchannel_vary_chpid(struct subchannel *sch, __u8 chpid, int on)
 {
        int chp, old_lpm;
@@ -967,8 +959,8 @@ static struct bin_attribute chp_measurement_attr = {
 static void
 chsc_remove_chp_cmg_attr(struct channel_path *chp)
 {
-       sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_chars_attr);
-       sysfs_remove_bin_file(&chp->dev.kobj, &chp_measurement_attr);
+       device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
+       device_remove_bin_file(&chp->dev, &chp_measurement_attr);
 }
 
 static int
@@ -976,14 +968,12 @@ chsc_add_chp_cmg_attr(struct channel_path *chp)
 {
        int ret;
 
-       ret = sysfs_create_bin_file(&chp->dev.kobj,
-                                   &chp_measurement_chars_attr);
+       ret = device_create_bin_file(&chp->dev, &chp_measurement_chars_attr);
        if (ret)
                return ret;
-       ret = sysfs_create_bin_file(&chp->dev.kobj, &chp_measurement_attr);
+       ret = device_create_bin_file(&chp->dev, &chp_measurement_attr);
        if (ret)
-               sysfs_remove_bin_file(&chp->dev.kobj,
-                                     &chp_measurement_chars_attr);
+               device_remove_bin_file(&chp->dev, &chp_measurement_chars_attr);
        return ret;
 }
 
@@ -1042,7 +1032,7 @@ __chsc_do_secm(struct channel_subsystem *css, int enable, void *page)
                u32 : 4;
                u32 fmt : 4;
                u32 : 16;
-       } *secm_area;
+       } __attribute__ ((packed)) *secm_area;
        int ret, ccode;
 
        secm_area = page;
@@ -1253,7 +1243,7 @@ chsc_determine_channel_path_description(int chpid,
                struct chsc_header response;
                u32 zeroes2;
                struct channel_path_desc desc;
-       } *scpd_area;
+       } __attribute__ ((packed)) *scpd_area;
 
        scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
        if (!scpd_area)
@@ -1350,7 +1340,7 @@ chsc_get_channel_measurement_chars(struct channel_path *chp)
                u32 cmg : 8;
                u32 zeroes3;
                u32 data[NR_MEASUREMENT_CHARS];
-       } *scmc_area;
+       } __attribute__ ((packed)) *scmc_area;
 
        scmc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
        if (!scmc_area)
@@ -1517,7 +1507,7 @@ chsc_enable_facility(int operation_code)
                u32 reserved5:4;
                u32 format2:4;
                u32 reserved6:24;
-       } *sda_area;
+       } __attribute__ ((packed)) *sda_area;
 
        sda_area = (void *)get_zeroed_page(GFP_KERNEL|GFP_DMA);
        if (!sda_area)
@@ -1569,7 +1559,7 @@ chsc_determine_css_characteristics(void)
                u32 reserved4;
                u32 general_char[510];
                u32 chsc_char[518];
-       } *scsc_area;
+       } __attribute__ ((packed)) *scsc_area;
 
        scsc_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
        if (!scsc_area) {
index a259245..0fb2b02 100644 (file)
 struct chsc_header {
        u16 length;
        u16 code;
-};
+} __attribute__ ((packed));
 
 #define NR_MEASUREMENT_CHARS 5
 struct cmg_chars {
        u32 values[NR_MEASUREMENT_CHARS];
-};
+} __attribute__ ((packed));
 
 #define NR_MEASUREMENT_ENTRIES 8
 struct cmg_entry {
        u32 values[NR_MEASUREMENT_ENTRIES];
-};
+} __attribute__ ((packed));
 
 struct channel_path_desc {
        u8 flags;
@@ -31,7 +31,7 @@ struct channel_path_desc {
        u8 zeroes;
        u8 chla;
        u8 chpp;
-};
+} __attribute__ ((packed));
 
 struct channel_path {
        int id;
@@ -47,6 +47,9 @@ struct channel_path {
 extern void s390_process_css( void );
 extern void chsc_validate_chpids(struct subchannel *);
 extern void chpid_is_actually_online(int);
+extern int css_get_ssd_info(struct subchannel *);
+extern int chsc_process_crw(void);
+extern int chp_process_crw(int, int);
 
 struct css_general_char {
        u64 : 41;
index ae1bf23..b3a56dc 100644 (file)
@@ -122,7 +122,7 @@ cio_get_options (struct subchannel *sch)
  * Use tpi to get a pending interrupt, call the interrupt handler and
  * return a pointer to the subchannel structure.
  */
-static inline int
+static int
 cio_tpi(void)
 {
        struct tpi_info *tpi_info;
@@ -152,7 +152,7 @@ cio_tpi(void)
        return 1;
 }
 
-static inline int
+static int
 cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
 {
        char dbf_text[15];
@@ -585,7 +585,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
                 * This device must not be known to Linux. So we simply
                 * say that there is no device and return ENODEV.
                 */
-               CIO_MSG_EVENT(0, "Blacklisted device detected "
+               CIO_MSG_EVENT(4, "Blacklisted device detected "
                              "at devno %04X, subchannel set %x\n",
                              sch->schib.pmcw.dev, sch->schid.ssid);
                err = -ENODEV;
@@ -646,7 +646,7 @@ do_IRQ (struct pt_regs *regs)
                 * Make sure that the i/o interrupt did not "overtake"
                 * the last HZ timer interrupt.
                 */
-               account_ticks();
+               account_ticks(S390_lowcore.int_clock);
        /*
         * Get interrupt information from lowcore
         */
@@ -832,7 +832,7 @@ cio_get_console_subchannel(void)
 }
 
 #endif
-static inline int
+static int
 __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
 {
        int retry, cc;
@@ -850,7 +850,20 @@ __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib)
        return -EBUSY; /* uhm... */
 }
 
-static inline int
+/* we can't use the normal udelay here, since it enables external interrupts */
+
+static void udelay_reset(unsigned long usecs)
+{
+       uint64_t start_cc, end_cc;
+
+       asm volatile ("STCK %0" : "=m" (start_cc));
+       do {
+               cpu_relax();
+               asm volatile ("STCK %0" : "=m" (end_cc));
+       } while (((end_cc - start_cc)/4096) < usecs);
+}
+
+static int
 __clear_subchannel_easy(struct subchannel_id schid)
 {
        int retry;
@@ -865,7 +878,7 @@ __clear_subchannel_easy(struct subchannel_id schid)
                        if (schid_equal(&ti.schid, &schid))
                                return 0;
                }
-               udelay(100);
+               udelay_reset(100);
        }
        return -EBUSY;
 }
@@ -882,11 +895,11 @@ static int stsch_reset(struct subchannel_id schid, volatile struct schib *addr)
        int rc;
 
        pgm_check_occured = 0;
-       s390_reset_pgm_handler = cio_reset_pgm_check_handler;
+       s390_base_pgm_handler_fn = cio_reset_pgm_check_handler;
        rc = stsch(schid, addr);
-       s390_reset_pgm_handler = NULL;
+       s390_base_pgm_handler_fn = NULL;
 
-       /* The program check handler could have changed pgm_check_occured */
+       /* The program check handler could have changed pgm_check_occured. */
        barrier();
 
        if (pgm_check_occured)
@@ -944,7 +957,7 @@ static void css_reset(void)
        /* Reset subchannels. */
        for_each_subchannel(__shutdown_subchannel_easy,  NULL);
        /* Reset channel paths. */
-       s390_reset_mcck_handler = s390_reset_chpids_mcck_handler;
+       s390_base_mcck_handler_fn = s390_reset_chpids_mcck_handler;
        /* Enable channel report machine checks. */
        __ctl_set_bit(14, 28);
        /* Temporarily reenable machine checks. */
@@ -969,7 +982,7 @@ static void css_reset(void)
        local_mcck_disable();
        /* Disable channel report machine checks. */
        __ctl_clear_bit(14, 28);
-       s390_reset_mcck_handler = NULL;
+       s390_base_mcck_handler_fn = NULL;
 }
 
 static struct reset_call css_reset_call = {
index 828b2d3..90b22fa 100644 (file)
@@ -519,8 +519,8 @@ struct cmb {
 /* insert a single device into the cmb_area list
  * called with cmb_area.lock held from alloc_cmb
  */
-static inline int alloc_cmb_single (struct ccw_device *cdev,
-                                   struct cmb_data *cmb_data)
+static int alloc_cmb_single(struct ccw_device *cdev,
+                           struct cmb_data *cmb_data)
 {
        struct cmb *cmb;
        struct ccw_device_private *node;
index 9d6c024..fe0ace7 100644 (file)
@@ -30,7 +30,7 @@ struct channel_subsystem *css[__MAX_CSSID + 1];
 
 int css_characteristics_avail = 0;
 
-inline int
+int
 for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
 {
        struct subchannel_id schid;
@@ -108,9 +108,6 @@ css_subchannel_release(struct device *dev)
        }
 }
 
-extern int css_get_ssd_info(struct subchannel *sch);
-
-
 int css_sch_device_register(struct subchannel *sch)
 {
        int ret;
@@ -187,7 +184,7 @@ get_subchannel_by_schid(struct subchannel_id schid)
        return dev ? to_subchannel(dev) : NULL;
 }
 
-static inline int css_get_subchannel_status(struct subchannel *sch)
+static int css_get_subchannel_status(struct subchannel *sch)
 {
        struct schib schib;
 
@@ -299,7 +296,7 @@ static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
                /* Will be done on the slow path. */
                return -EAGAIN;
        }
-       if (stsch(schid, &schib) || !schib.pmcw.dnv) {
+       if (stsch_err(schid, &schib) || !schib.pmcw.dnv) {
                /* Unusable - ignore. */
                return 0;
        }
@@ -417,7 +414,7 @@ static void reprobe_all(struct work_struct *unused)
                      need_reprobe);
 }
 
-DECLARE_WORK(css_reprobe_work, reprobe_all);
+static DECLARE_WORK(css_reprobe_work, reprobe_all);
 
 /* Schedule reprobing of all unregistered subchannels. */
 void css_schedule_reprobe(void)
@@ -578,7 +575,7 @@ css_cm_enable_store(struct device *dev, struct device_attribute *attr,
 
 static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store);
 
-static inline int __init setup_css(int nr)
+static int __init setup_css(int nr)
 {
        u32 tod_high;
        int ret;
index 3464c5b..ca2bab9 100644 (file)
@@ -143,6 +143,8 @@ extern void css_sch_device_unregister(struct subchannel *);
 extern struct subchannel * get_subchannel_by_schid(struct subchannel_id);
 extern int css_init_done;
 extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
+extern int css_process_crw(int, int);
+extern void css_reiterate_subchannels(void);
 
 #define __MAX_SUBCHANNEL 65535
 #define __MAX_SSID 3
index 8035790..e322111 100644 (file)
@@ -138,7 +138,6 @@ struct bus_type ccw_bus_type;
 
 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 *);
@@ -235,11 +234,8 @@ chpids_show (struct device * dev, struct device_attribute *attr, char * buf)
        ssize_t ret = 0;
        int chp;
 
-       if (ssd)
-               for (chp = 0; chp < 8; chp++)
-                       ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]);
-       else
-               ret += sprintf (buf, "n/a");
+       for (chp = 0; chp < 8; chp++)
+               ret += sprintf (buf+ret, "%02x ", ssd->chpid[chp]);
        ret += sprintf (buf+ret, "\n");
        return min((ssize_t)PAGE_SIZE, ret);
 }
@@ -552,13 +548,13 @@ static struct attribute_group ccwdev_attr_group = {
        .attrs = ccwdev_attrs,
 };
 
-static inline int
+static int
 device_add_files (struct device *dev)
 {
        return sysfs_create_group(&dev->kobj, &ccwdev_attr_group);
 }
 
-static inline void
+static void
 device_remove_files(struct device *dev)
 {
        sysfs_remove_group(&dev->kobj, &ccwdev_attr_group);
index 29db634..b66338b 100644 (file)
@@ -74,6 +74,7 @@ extern struct workqueue_struct *ccw_device_notify_work;
 extern wait_queue_head_t ccw_device_init_wq;
 extern atomic_t ccw_device_init_count;
 
+void io_subchannel_irq (struct device *pdev);
 void io_subchannel_recog_done(struct ccw_device *cdev);
 
 int ccw_device_cancel_halt_clear(struct ccw_device *);
@@ -118,6 +119,7 @@ int ccw_device_stlck(struct ccw_device *);
 /* qdio needs this. */
 void ccw_device_set_timeout(struct ccw_device *, int);
 extern struct subchannel_id ccw_device_get_subchannel_id(struct ccw_device *);
+extern struct bus_type ccw_bus_type;
 
 /* Channel measurement facility related */
 void retry_set_schib(struct ccw_device *cdev);
index eed1457..51238e7 100644 (file)
@@ -206,7 +206,7 @@ ccw_device_handle_oper(struct ccw_device *cdev)
  * been varied online on the SE so we have to find out by magic (i. e. driving
  * the channel subsystem to device selection and updating our path masks).
  */
-static inline void
+static void
 __recover_lost_chpids(struct subchannel *sch, int old_lpm)
 {
        int mask, i;
@@ -387,7 +387,7 @@ ccw_device_done(struct ccw_device *cdev, int state)
                put_device (&cdev->dev);
 }
 
-static inline int cmp_pgid(struct pgid *p1, struct pgid *p2)
+static int cmp_pgid(struct pgid *p1, struct pgid *p2)
 {
        char *c1;
        char *c2;
@@ -842,6 +842,8 @@ ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
 call_handler_unsol:
                if (cdev->handler)
                        cdev->handler (cdev, 0, irb);
+               if (cdev->private->flags.doverify)
+                       ccw_device_online_verify(cdev, 0);
                return;
        }
        /* Accumulate status and find out if a basic sense is needed. */
@@ -892,7 +894,7 @@ ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
 /*
  * Got an interrupt for a basic sense.
  */
-void
+static void
 ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
 {
        struct irb *irb;
index d269607..d7b25b8 100644 (file)
@@ -302,7 +302,7 @@ ccw_device_wake_up(struct ccw_device *cdev, unsigned long ip, struct irb *irb)
        wake_up(&cdev->private->wait_q);
 }
 
-static inline int
+static int
 __ccw_device_retry_loop(struct ccw_device *cdev, struct ccw1 *ccw, long magic, __u8 lpm)
 {
        int ret;
index bdcf930..6b1caea 100644 (file)
@@ -25,7 +25,7 @@
  * Check for any kind of channel or interface control check but don't
  * issue the message for the console device
  */
-static inline void
+static void
 ccw_device_msg_control_check(struct ccw_device *cdev, struct irb *irb)
 {
        if (!(irb->scsw.cstat & (SCHN_STAT_CHN_DATA_CHK |
@@ -72,7 +72,7 @@ ccw_device_path_notoper(struct ccw_device *cdev)
 /*
  * Copy valid bits from the extended control word to device irb.
  */
-static inline void
+static void
 ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
 {
        /*
@@ -94,7 +94,7 @@ ccw_device_accumulate_ecw(struct ccw_device *cdev, struct irb *irb)
 /*
  * Check if extended status word is valid.
  */
-static inline int
+static int
 ccw_device_accumulate_esw_valid(struct irb *irb)
 {
        if (!irb->scsw.eswf && irb->scsw.stctl == SCSW_STCTL_STATUS_PEND)
@@ -109,7 +109,7 @@ ccw_device_accumulate_esw_valid(struct irb *irb)
 /*
  * Copy valid bits from the extended status word to device irb.
  */
-static inline void
+static void
 ccw_device_accumulate_esw(struct ccw_device *cdev, struct irb *irb)
 {
        struct irb *cdev_irb;
index 6fd1940..d726cd5 100644 (file)
@@ -66,7 +66,6 @@ MODULE_LICENSE("GPL");
 /******************** HERE WE GO ***********************************/
 
 static const char version[] = "QDIO base support version 2";
-extern struct bus_type ccw_bus_type;
 
 static int qdio_performance_stats = 0;
 static int proc_perf_file_registration;
@@ -138,7 +137,7 @@ qdio_release_q(struct qdio_q *q)
 }
 
 /*check ccq  */
-static inline int
+static int
 qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
 {
        char dbf_text[15];
@@ -153,7 +152,7 @@ qdio_check_ccq(struct qdio_q *q, unsigned int ccq)
        return -EIO;
 }
 /* EQBS: extract buffer states */
-static inline int
+static int
 qdio_do_eqbs(struct qdio_q *q, unsigned char *state,
             unsigned int *start, unsigned int *cnt)
 {
@@ -188,7 +187,7 @@ again:
 }
 
 /* SQBS: set buffer states */
-static inline int
+static int
 qdio_do_sqbs(struct qdio_q *q, unsigned char state,
             unsigned int *start, unsigned int *cnt)
 {
@@ -315,7 +314,7 @@ __do_siga_output(struct qdio_q *q, unsigned int *busy_bit)
  * returns QDIO_SIGA_ERROR_ACCESS_EXCEPTION as cc, when SIGA returns
  * an access exception 
  */
-static inline int 
+static int
 qdio_siga_output(struct qdio_q *q)
 {
        int cc;
@@ -349,7 +348,7 @@ qdio_siga_output(struct qdio_q *q)
        return cc;
 }
 
-static inline int 
+static int
 qdio_siga_input(struct qdio_q *q)
 {
        int cc;
@@ -421,7 +420,7 @@ tiqdio_sched_tl(void)
        tasklet_hi_schedule(&tiqdio_tasklet);
 }
 
-static inline void
+static void
 qdio_mark_tiq(struct qdio_q *q)
 {
        unsigned long flags;
@@ -471,7 +470,7 @@ qdio_mark_q(struct qdio_q *q)
        tasklet_schedule(&q->tasklet);
 }
 
-static inline int
+static int
 qdio_stop_polling(struct qdio_q *q)
 {
 #ifdef QDIO_USE_PROCESSING_STATE
@@ -525,7 +524,7 @@ qdio_stop_polling(struct qdio_q *q)
  * sophisticated locking outside of unmark_q, so that we don't need to
  * disable the interrupts :-) 
 */
-static inline void
+static void
 qdio_unmark_q(struct qdio_q *q)
 {
        unsigned long flags;
@@ -691,7 +690,7 @@ qdio_qebsm_get_inbound_buffer_frontier(struct qdio_q *q)
         return q->first_to_check;
 }
 
-static inline int
+static int
 qdio_get_outbound_buffer_frontier(struct qdio_q *q)
 {
        struct qdio_irq *irq;
@@ -774,7 +773,7 @@ out:
 }
 
 /* all buffers are processed */
-static inline int
+static int
 qdio_is_outbound_q_done(struct qdio_q *q)
 {
        int no_used;
@@ -796,7 +795,7 @@ qdio_is_outbound_q_done(struct qdio_q *q)
        return (no_used==0);
 }
 
-static inline int
+static int
 qdio_has_outbound_q_moved(struct qdio_q *q)
 {
        int i;
@@ -816,7 +815,7 @@ qdio_has_outbound_q_moved(struct qdio_q *q)
        }
 }
 
-static inline void
+static void
 qdio_kick_outbound_q(struct qdio_q *q)
 {
        int result;
@@ -905,7 +904,7 @@ qdio_kick_outbound_q(struct qdio_q *q)
        }
 }
 
-static inline void
+static void
 qdio_kick_outbound_handler(struct qdio_q *q)
 {
        int start, end, real_end, count;
@@ -942,7 +941,7 @@ qdio_kick_outbound_handler(struct qdio_q *q)
        q->error_status_flags=0;
 }
 
-static inline void
+static void
 __qdio_outbound_processing(struct qdio_q *q)
 {
        int siga_attempts;
@@ -1002,7 +1001,7 @@ qdio_outbound_processing(struct qdio_q *q)
 /************************* INBOUND ROUTINES *******************************/
 
 
-static inline int
+static int
 qdio_get_inbound_buffer_frontier(struct qdio_q *q)
 {
        struct qdio_irq *irq;
@@ -1133,7 +1132,7 @@ out:
        return q->first_to_check;
 }
 
-static inline int
+static int
 qdio_has_inbound_q_moved(struct qdio_q *q)
 {
        int i;
@@ -1167,7 +1166,7 @@ qdio_has_inbound_q_moved(struct qdio_q *q)
 }
 
 /* means, no more buffers to be filled */
-static inline int
+static int
 tiqdio_is_inbound_q_done(struct qdio_q *q)
 {
        int no_used;
@@ -1228,7 +1227,7 @@ tiqdio_is_inbound_q_done(struct qdio_q *q)
        return 0;
 }
 
-static inline int
+static int
 qdio_is_inbound_q_done(struct qdio_q *q)
 {
        int no_used;
@@ -1296,7 +1295,7 @@ qdio_is_inbound_q_done(struct qdio_q *q)
        }
 }
 
-static inline void
+static void
 qdio_kick_inbound_handler(struct qdio_q *q)
 {
        int count, start, end, real_end, i;
@@ -1343,7 +1342,7 @@ qdio_kick_inbound_handler(struct qdio_q *q)
        }
 }
 
-static inline void
+static void
 __tiqdio_inbound_processing(struct qdio_q *q, int spare_ind_was_set)
 {
        struct qdio_irq *irq_ptr;
@@ -1442,7 +1441,7 @@ tiqdio_inbound_processing(struct qdio_q *q)
        __tiqdio_inbound_processing(q, atomic_read(&spare_indicator_usecount));
 }
 
-static inline void
+static void
 __qdio_inbound_processing(struct qdio_q *q)
 {
        int q_laps=0;
@@ -1493,7 +1492,7 @@ qdio_inbound_processing(struct qdio_q *q)
 /************************* MAIN ROUTINES *******************************/
 
 #ifdef QDIO_USE_PROCESSING_STATE
-static inline int
+static int
 tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
 {
        if (!q) {
@@ -1545,7 +1544,7 @@ tiqdio_reset_processing_state(struct qdio_q *q, int q_laps)
 }
 #endif /* QDIO_USE_PROCESSING_STATE */
 
-static inline void
+static void
 tiqdio_inbound_checks(void)
 {
        struct qdio_q *q;
@@ -1949,7 +1948,7 @@ qdio_set_state(struct qdio_irq *irq_ptr, enum qdio_irq_states state)
        mb();
 }
 
-static inline void
+static void
 qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb)
 {
        char dbf_text[15];
@@ -1966,7 +1965,7 @@ qdio_irq_check_sense(struct subchannel_id schid, struct irb *irb)
                
 }
 
-static inline void
+static void
 qdio_handle_pci(struct qdio_irq *irq_ptr)
 {
        int i;
@@ -2002,7 +2001,7 @@ qdio_handle_pci(struct qdio_irq *irq_ptr)
 
 static void qdio_establish_handle_irq(struct ccw_device*, int, int);
 
-static inline void
+static void
 qdio_handle_activate_check(struct ccw_device *cdev, unsigned long intparm,
                           int cstat, int dstat)
 {
@@ -2229,7 +2228,7 @@ qdio_synchronize(struct ccw_device *cdev, unsigned int flags,
        return cc;
 }
 
-static inline void
+static void
 qdio_check_subchannel_qebsm(struct qdio_irq *irq_ptr, unsigned char qdioac,
                            unsigned long token)
 {
@@ -2740,7 +2739,7 @@ qdio_free(struct ccw_device *cdev)
        return 0;
 }
 
-static inline void
+static void
 qdio_allocate_do_dbf(struct qdio_initialize *init_data)
 {
        char dbf_text[20]; /* if a printf printed out more than 8 chars */
@@ -2773,7 +2772,7 @@ qdio_allocate_do_dbf(struct qdio_initialize *init_data)
        QDIO_DBF_HEX0(0,setup,&init_data->output_sbal_addr_array,sizeof(void*));
 }
 
-static inline void
+static void
 qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
 {
        irq_ptr->input_qs[i]->is_iqdio_q = iqfmt;
@@ -2792,7 +2791,7 @@ qdio_allocate_fill_input_desc(struct qdio_irq *irq_ptr, int i, int iqfmt)
        irq_ptr->qdr->qdf0[i].dkey=QDIO_STORAGE_KEY;
 }
 
-static inline void
+static void
 qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i,
                               int j, int iqfmt)
 {
@@ -2813,7 +2812,7 @@ qdio_allocate_fill_output_desc(struct qdio_irq *irq_ptr, int i,
 }
 
 
-static inline void
+static void
 qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr)
 {
        int i;
@@ -2839,7 +2838,7 @@ qdio_initialize_set_siga_flags_input(struct qdio_irq *irq_ptr)
        }
 }
 
-static inline void
+static void
 qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr)
 {
        int i;
@@ -2865,7 +2864,7 @@ qdio_initialize_set_siga_flags_output(struct qdio_irq *irq_ptr)
        }
 }
 
-static inline int
+static int
 qdio_establish_irq_check_for_errors(struct ccw_device *cdev, int cstat,
                                    int dstat)
 {
@@ -3014,7 +3013,7 @@ qdio_allocate(struct qdio_initialize *init_data)
        return 0;
 }
 
-int qdio_fill_irq(struct qdio_initialize *init_data)
+static int qdio_fill_irq(struct qdio_initialize *init_data)
 {
        int i;
        char dbf_text[15];
@@ -3367,7 +3366,7 @@ qdio_activate(struct ccw_device *cdev, int flags)
 }
 
 /* buffers filled forwards again to make Rick happy */
-static inline void
+static void
 qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx,
                        unsigned int count, struct qdio_buffer *buffers)
 {
@@ -3386,7 +3385,7 @@ qdio_do_qdio_fill_input(struct qdio_q *q, unsigned int qidx,
        }
 }
 
-static inline void
+static void
 qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx,
                         unsigned int count, struct qdio_buffer *buffers)
 {
@@ -3407,7 +3406,7 @@ qdio_do_qdio_fill_output(struct qdio_q *q, unsigned int qidx,
        }
 }
 
-static inline void
+static void
 do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags,
                       unsigned int qidx, unsigned int count,
                       struct qdio_buffer *buffers)
@@ -3443,7 +3442,7 @@ do_qdio_handle_inbound(struct qdio_q *q, unsigned int callflags,
        qdio_mark_q(q);
 }
 
-static inline void
+static void
 do_qdio_handle_outbound(struct qdio_q *q, unsigned int callflags,
                        unsigned int qidx, unsigned int count,
                        struct qdio_buffer *buffers)
index 81b5899..c7d1355 100644 (file)
@@ -465,7 +465,7 @@ static int ap_device_probe(struct device *dev)
  * Flush all requests from the request/pending queue of an AP device.
  * @ap_dev: pointer to the AP device.
  */
-static inline void __ap_flush_queue(struct ap_device *ap_dev)
+static void __ap_flush_queue(struct ap_device *ap_dev)
 {
        struct ap_message *ap_msg, *next;
 
@@ -587,7 +587,7 @@ static struct bus_attribute *const ap_bus_attrs[] = {
 /**
  * Pick one of the 16 ap domains.
  */
-static inline int ap_select_domain(void)
+static int ap_select_domain(void)
 {
        int queue_depth, device_type, count, max_count, best_domain;
        int rc, i, j;
@@ -825,7 +825,7 @@ static inline void ap_schedule_poll_timer(void)
  *        required, bit 2^1 is set if the poll timer needs to get armed
  * Returns 0 if the device is still present, -ENODEV if not.
  */
-static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
+static int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
 {
        struct ap_queue_status status;
        struct ap_message *ap_msg;
@@ -872,7 +872,7 @@ static inline int ap_poll_read(struct ap_device *ap_dev, unsigned long *flags)
  *        required, bit 2^1 is set if the poll timer needs to get armed
  * Returns 0 if the device is still present, -ENODEV if not.
  */
-static inline int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
+static int ap_poll_write(struct ap_device *ap_dev, unsigned long *flags)
 {
        struct ap_queue_status status;
        struct ap_message *ap_msg;
index 1edc10a..b9e59bc 100644 (file)
@@ -791,7 +791,7 @@ static long trans_xcRB32(struct file *filp, unsigned int cmd,
        return rc;
 }
 
-long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
+static long zcrypt_compat_ioctl(struct file *filp, unsigned int cmd,
                         unsigned long arg)
 {
        if (cmd == ICARSAMODEXPO)
@@ -833,8 +833,8 @@ static struct miscdevice zcrypt_misc_device = {
  */
 static struct proc_dir_entry *zcrypt_entry;
 
-static inline int sprintcl(unsigned char *outaddr, unsigned char *addr,
-                          unsigned int len)
+static int sprintcl(unsigned char *outaddr, unsigned char *addr,
+                   unsigned int len)
 {
        int hl, i;
 
@@ -845,8 +845,8 @@ static inline int sprintcl(unsigned char *outaddr, unsigned char *addr,
        return hl;
 }
 
-static inline int sprintrw(unsigned char *outaddr, unsigned char *addr,
-                          unsigned int len)
+static int sprintrw(unsigned char *outaddr, unsigned char *addr,
+                   unsigned int len)
 {
        int hl, inl, c, cx;
 
@@ -865,8 +865,8 @@ static inline int sprintrw(unsigned char *outaddr, unsigned char *addr,
        return hl;
 }
 
-static inline int sprinthx(unsigned char *title, unsigned char *outaddr,
-                          unsigned char *addr, unsigned int len)
+static int sprinthx(unsigned char *title, unsigned char *outaddr,
+                   unsigned char *addr, unsigned int len)
 {
        int hl, inl, r, rx;
 
@@ -885,8 +885,8 @@ static inline int sprinthx(unsigned char *title, unsigned char *outaddr,
        return hl;
 }
 
-static inline int sprinthx4(unsigned char *title, unsigned char *outaddr,
-                           unsigned int *array, unsigned int len)
+static int sprinthx4(unsigned char *title, unsigned char *outaddr,
+                    unsigned int *array, unsigned int len)
 {
        int hl, r;
 
@@ -943,7 +943,7 @@ static int zcrypt_status_read(char *resp_buff, char **start, off_t offset,
        zcrypt_qdepth_mask(workarea);
        len += sprinthx("Waiting work element counts",
                        resp_buff+len, workarea, AP_DEVICES);
-       zcrypt_perdev_reqcnt((unsigned int *) workarea);
+       zcrypt_perdev_reqcnt((int *) workarea);
        len += sprinthx4("Per-device successfully completed request counts",
                         resp_buff+len,(unsigned int *) workarea, AP_DEVICES);
        *eof = 1;
index 32e3701..818ffe0 100644 (file)
@@ -191,10 +191,10 @@ static int ICACRT_msg_to_type4CRT_msg(struct zcrypt_device *zdev,
  *
  * Returns 0 on success or -EFAULT.
  */
-static inline int convert_type84(struct zcrypt_device *zdev,
-                                struct ap_message *reply,
-                                char __user *outputdata,
-                                unsigned int outputdatalength)
+static int convert_type84(struct zcrypt_device *zdev,
+                         struct ap_message *reply,
+                         char __user *outputdata,
+                         unsigned int outputdatalength)
 {
        struct type84_hdr *t84h = reply->message;
        char *data;
index b7153c1..252443b 100644 (file)
@@ -709,7 +709,8 @@ out_free:
  *       PCIXCC/CEX2C device to the request distributor
  * @xcRB: pointer to the send_cprb request buffer
  */
-long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev, struct ica_xcRB *xcRB)
+static long zcrypt_pcixcc_send_cprb(struct zcrypt_device *zdev,
+                                   struct ica_xcRB *xcRB)
 {
        struct ap_message ap_msg;
        struct response_type resp_type = {
index 95f4e10..7809a79 100644 (file)
@@ -121,7 +121,7 @@ MODULE_LICENSE("GPL");
 #define DEBUG
 #endif
 
- char debug_buffer[255];
+static char debug_buffer[255];
 /**
  * Debug Facility Stuff
  */
@@ -223,16 +223,14 @@ static void claw_timer ( struct chbk * p_ch );
 /* Functions */
 static int add_claw_reads(struct net_device *dev,
        struct ccwbk* p_first, struct ccwbk* p_last);
-static void inline ccw_check_return_code (struct ccw_device *cdev,
-        int return_code);
-static void inline ccw_check_unit_check (struct chbk * p_ch,
-       unsigned char sense );
+static void ccw_check_return_code (struct ccw_device *cdev, int return_code);
+static void ccw_check_unit_check (struct chbk * p_ch, unsigned char sense );
 static int find_link(struct net_device *dev, char *host_name, char *ws_name );
 static int claw_hw_tx(struct sk_buff *skb, struct net_device *dev, long linkid);
 static int init_ccw_bk(struct net_device *dev);
 static void probe_error( struct ccwgroup_device *cgdev);
 static struct net_device_stats *claw_stats(struct net_device *dev);
-static int inline pages_to_order_of_mag(int num_of_pages);
+static int pages_to_order_of_mag(int num_of_pages);
 static struct sk_buff *claw_pack_skb(struct claw_privbk *privptr);
 #ifdef DEBUG
 static void dumpit (char *buf, int len);
@@ -1310,7 +1308,7 @@ claw_timer ( struct chbk * p_ch )
 *    of magnitude get_free_pages() has an upper order of 9           *
 *--------------------------------------------------------------------*/
 
-static int inline
+static int
 pages_to_order_of_mag(int num_of_pages)
 {
        int     order_of_mag=1;         /* assume 2 pages */
@@ -1482,7 +1480,7 @@ add_claw_reads(struct net_device *dev, struct ccwbk* p_first,
  *                                                                   *
  *-------------------------------------------------------------------*/
 
-static void inline
+static void
 ccw_check_return_code(struct ccw_device *cdev, int return_code)
 {
 #ifdef FUNCTRACE
@@ -1529,7 +1527,7 @@ ccw_check_return_code(struct ccw_device *cdev, int return_code)
 *       ccw_check_unit_check                                         *
 *--------------------------------------------------------------------*/
 
-static void inline
+static void
 ccw_check_unit_check(struct chbk * p_ch, unsigned char sense )
 {
        struct net_device *dev = p_ch->ndev;
index 03cc263..5a84fbb 100644 (file)
@@ -369,7 +369,7 @@ ctc_dump_skb(struct sk_buff *skb, int offset)
  * @param ch The channel where this skb has been received.
  * @param pskb The received skb.
  */
-static __inline__ void
+static void
 ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
 {
        struct net_device *dev = ch->netdev;
@@ -512,7 +512,7 @@ ctc_unpack_skb(struct channel *ch, struct sk_buff *pskb)
  * @param ch          The channel, the error belongs to.
  * @param return_code The error code to inspect.
  */
-static void inline
+static void
 ccw_check_return_code(struct channel *ch, int return_code, char *msg)
 {
        DBF_TEXT(trace, 5, __FUNCTION__);
@@ -547,7 +547,7 @@ ccw_check_return_code(struct channel *ch, int return_code, char *msg)
  * @param ch    The channel, the sense code belongs to.
  * @param sense The sense code to inspect.
  */
-static void inline
+static void
 ccw_unit_check(struct channel *ch, unsigned char sense)
 {
        DBF_TEXT(trace, 5, __FUNCTION__);
@@ -603,7 +603,7 @@ ctc_purge_skb_queue(struct sk_buff_head *q)
        }
 }
 
-static __inline__ int
+static int
 ctc_checkalloc_buffer(struct channel *ch, int warn)
 {
        DBF_TEXT(trace, 5, __FUNCTION__);
index e965f03..76728ae 100644 (file)
@@ -57,7 +57,7 @@ static struct ccw_device_id cu3088_ids[] = {
 
 static struct ccw_driver cu3088_driver;
 
-struct device *cu3088_root_dev;
+static struct device *cu3088_root_dev;
 
 static ssize_t
 group_write(struct device_driver *drv, const char *buf, size_t count)
index e5665b6..b97dd15 100644 (file)
@@ -828,7 +828,7 @@ lcs_notify_lancmd_waiters(struct lcs_card *card, struct lcs_cmd *cmd)
 /**
  * Emit buffer of a lan comand.
  */
-void
+static void
 lcs_lancmd_timeout(unsigned long data)
 {
        struct lcs_reply *reply, *list_reply, *r;
@@ -1360,7 +1360,7 @@ lcs_get_problem(struct ccw_device *cdev, struct irb *irb)
        return 0;
 }
 
-void
+static void
 lcs_schedule_recovery(struct lcs_card *card)
 {
        LCS_DBF_TEXT(2, trace, "startrec");
@@ -1990,7 +1990,7 @@ lcs_timeout_store (struct device *dev, struct device_attribute *attr, const char
 
 }
 
-DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);
+static DEVICE_ATTR(lancmd_timeout, 0644, lcs_timeout_show, lcs_timeout_store);
 
 static ssize_t
 lcs_dev_recover_store(struct device *dev, struct device_attribute *attr,
index d7d1cc0..3346088 100644 (file)
@@ -2053,7 +2053,7 @@ out_free_ndev:
        return ret;
 }
 
-DRIVER_ATTR(connection, 0200, NULL, conn_write);
+static DRIVER_ATTR(connection, 0200, NULL, conn_write);
 
 static ssize_t
 remove_write (struct device_driver *drv, const char *buf, size_t count)
@@ -2112,7 +2112,7 @@ remove_write (struct device_driver *drv, const char *buf, size_t count)
         return -EINVAL;
 }
 
-DRIVER_ATTR(remove, 0200, NULL, remove_write);
+static DRIVER_ATTR(remove, 0200, NULL, remove_write);
 
 static void
 netiucv_banner(void)
index 6bb558a..7c735e1 100644 (file)
@@ -49,7 +49,7 @@ qeth_eddp_check_buffers_for_context(struct qeth_qdio_out_q *queue,
        return buffers_needed;
 }
 
-static inline void
+static void
 qeth_eddp_free_context(struct qeth_eddp_context *ctx)
 {
        int i;
@@ -91,7 +91,7 @@ qeth_eddp_buf_release_contexts(struct qeth_qdio_out_buffer *buf)
        }
 }
 
-static inline int
+static int
 qeth_eddp_buf_ref_context(struct qeth_qdio_out_buffer *buf,
                          struct qeth_eddp_context *ctx)
 {
@@ -196,7 +196,7 @@ out:
        return flush_cnt;
 }
 
-static inline void
+static void
 qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
                              struct qeth_eddp_data *eddp, int data_len)
 {
@@ -256,7 +256,7 @@ qeth_eddp_create_segment_hdrs(struct qeth_eddp_context *ctx,
        ctx->offset += eddp->thl;
 }
 
-static inline void
+static void
 qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
                        __wsum *hcsum)
 {
@@ -302,7 +302,7 @@ qeth_eddp_copy_data_tcp(char *dst, struct qeth_eddp_data *eddp, int len,
        }
 }
 
-static inline void
+static void
 qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx,
                                  struct qeth_eddp_data *eddp, int data_len,
                                  __wsum hcsum)
@@ -349,7 +349,7 @@ qeth_eddp_create_segment_data_tcp(struct qeth_eddp_context *ctx,
        ((struct tcphdr *)eddp->th_in_ctx)->check = csum_fold(hcsum);
 }
 
-static inline __wsum
+static __wsum
 qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len)
 {
        __wsum phcsum; /* pseudo header checksum */
@@ -363,7 +363,7 @@ qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, int data_len)
        return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum);
 }
 
-static inline __wsum
+static __wsum
 qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len)
 {
        __be32 proto;
@@ -381,7 +381,7 @@ qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, int data_len)
        return phcsum;
 }
 
-static inline struct qeth_eddp_data *
+static struct qeth_eddp_data *
 qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl)
 {
        struct qeth_eddp_data *eddp;
@@ -399,7 +399,7 @@ qeth_eddp_create_eddp_data(struct qeth_hdr *qh, u8 *nh, u8 nhl, u8 *th, u8 thl)
        return eddp;
 }
 
-static inline void
+static void
 __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
                             struct qeth_eddp_data *eddp)
 {
@@ -464,7 +464,7 @@ __qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
        }
 }
 
-static inline int
+static int
 qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
                           struct sk_buff *skb, struct qeth_hdr *qhdr)
 {
@@ -505,7 +505,7 @@ qeth_eddp_fill_context_tcp(struct qeth_eddp_context *ctx,
        return 0;
 }
 
-static inline void
+static void
 qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
                         int hdr_len)
 {
@@ -529,7 +529,7 @@ qeth_eddp_calc_num_pages(struct qeth_eddp_context *ctx, struct sk_buff *skb,
                            (skb_shinfo(skb)->gso_segs + 1);
 }
 
-static inline struct qeth_eddp_context *
+static struct qeth_eddp_context *
 qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb,
                                 int hdr_len)
 {
@@ -581,7 +581,7 @@ qeth_eddp_create_context_generic(struct qeth_card *card, struct sk_buff *skb,
        return ctx;
 }
 
-static inline struct qeth_eddp_context *
+static struct qeth_eddp_context *
 qeth_eddp_create_context_tcp(struct qeth_card *card, struct sk_buff *skb,
                             struct qeth_hdr *qhdr)
 {
@@ -625,5 +625,3 @@ qeth_eddp_create_context(struct qeth_card *card, struct sk_buff *skb,
        }
        return NULL;
 }
-
-
index d2efa5f..2257e45 100644 (file)
@@ -651,7 +651,7 @@ __qeth_ref_ip_on_card(struct qeth_card *card, struct qeth_ipaddr *todo,
                return 0;
 }
 
-static inline int
+static int
 __qeth_address_exists_in_list(struct list_head *list, struct qeth_ipaddr *addr,
                              int same_type)
 {
@@ -795,7 +795,7 @@ qeth_add_ip(struct qeth_card *card, struct qeth_ipaddr *addr)
        return rc;
 }
 
-static inline void
+static void
 __qeth_delete_all_mc(struct qeth_card *card, unsigned long *flags)
 {
        struct qeth_ipaddr *addr, *tmp;
@@ -882,7 +882,7 @@ static void qeth_layer2_add_multicast(struct qeth_card *);
 static void qeth_add_multicast_ipv6(struct qeth_card *);
 #endif
 
-static inline int
+static int
 qeth_set_thread_start_bit(struct qeth_card *card, unsigned long thread)
 {
        unsigned long flags;
@@ -920,7 +920,7 @@ qeth_clear_thread_running_bit(struct qeth_card *card, unsigned long thread)
        wake_up(&card->wait_q);
 }
 
-static inline int
+static int
 __qeth_do_run_thread(struct qeth_card *card, unsigned long thread)
 {
        unsigned long flags;
@@ -1764,9 +1764,9 @@ out:
        qeth_release_buffer(channel,iob);
 }
 
-static inline void
+static void
 qeth_prepare_control_data(struct qeth_card *card, int len,
-struct qeth_cmd_buffer *iob)
+                         struct qeth_cmd_buffer *iob)
 {
        qeth_setup_ccw(&card->write,iob->data,len);
        iob->callback = qeth_release_buffer;
@@ -2160,7 +2160,7 @@ qeth_check_qdio_errors(struct qdio_buffer *buf, unsigned int qdio_error,
        return 0;
 }
 
-static inline struct sk_buff *
+static struct sk_buff *
 qeth_get_skb(unsigned int length, struct qeth_hdr *hdr)
 {
        struct sk_buff* skb;
@@ -2179,7 +2179,7 @@ qeth_get_skb(unsigned int length, struct qeth_hdr *hdr)
        return skb;
 }
 
-static inline struct sk_buff *
+static struct sk_buff *
 qeth_get_next_skb(struct qeth_card *card, struct qdio_buffer *buffer,
                  struct qdio_buffer_element **__element, int *__offset,
                  struct qeth_hdr **hdr)
@@ -2264,7 +2264,7 @@ no_mem:
        return NULL;
 }
 
-static inline __be16
+static __be16
 qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
        struct qeth_card *card;
@@ -2297,7 +2297,7 @@ qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
        return htons(ETH_P_802_2);
 }
 
-static inline void
+static void
 qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
                         struct qeth_hdr *hdr)
 {
@@ -2351,7 +2351,7 @@ qeth_rebuild_skb_fake_ll_tr(struct qeth_card *card, struct sk_buff *skb,
        fake_llc->ethertype = ETH_P_IP;
 }
 
-static inline void
+static void
 qeth_rebuild_skb_fake_ll_eth(struct qeth_card *card, struct sk_buff *skb,
                         struct qeth_hdr *hdr)
 {
@@ -2420,7 +2420,7 @@ qeth_layer2_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
        *((__u32 *)skb->cb) = ++card->seqno.pkt_seqno;
 }
 
-static inline __u16
+static __u16
 qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
                 struct qeth_hdr *hdr)
 {
@@ -2476,7 +2476,7 @@ qeth_rebuild_skb(struct qeth_card *card, struct sk_buff *skb,
        return vlan_id;
 }
 
-static inline void
+static void
 qeth_process_inbound_buffer(struct qeth_card *card,
                            struct qeth_qdio_buffer *buf, int index)
 {
@@ -2528,7 +2528,7 @@ qeth_process_inbound_buffer(struct qeth_card *card,
        }
 }
 
-static inline struct qeth_buffer_pool_entry *
+static struct qeth_buffer_pool_entry *
 qeth_get_buffer_pool_entry(struct qeth_card *card)
 {
        struct qeth_buffer_pool_entry *entry;
@@ -2543,7 +2543,7 @@ qeth_get_buffer_pool_entry(struct qeth_card *card)
        return NULL;
 }
 
-static inline void
+static void
 qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
 {
        struct qeth_buffer_pool_entry *pool_entry;
@@ -2570,7 +2570,7 @@ qeth_init_input_buffer(struct qeth_card *card, struct qeth_qdio_buffer *buf)
        buf->state = QETH_QDIO_BUF_EMPTY;
 }
 
-static inline void
+static void
 qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
                         struct qeth_qdio_out_buffer *buf)
 {
@@ -2595,7 +2595,7 @@ qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
        atomic_set(&buf->state, QETH_QDIO_BUF_EMPTY);
 }
 
-static inline void
+static void
 qeth_queue_input_buffer(struct qeth_card *card, int index)
 {
        struct qeth_qdio_q *queue = card->qdio.in_q;
@@ -2699,7 +2699,7 @@ qeth_qdio_input_handler(struct ccw_device * ccwdev, unsigned int status,
                        card->perf_stats.inbound_start_time;
 }
 
-static inline int
+static int
 qeth_handle_send_error(struct qeth_card *card,
                       struct qeth_qdio_out_buffer *buffer,
                       unsigned int qdio_err, unsigned int siga_err)
@@ -2821,7 +2821,7 @@ qeth_flush_buffers(struct qeth_qdio_out_q *queue, int under_int,
  * Switched to packing state if the number of used buffers on a queue
  * reaches a certain limit.
  */
-static inline void
+static void
 qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
 {
        if (!queue->do_pack) {
@@ -2842,7 +2842,7 @@ qeth_switch_to_packing_if_needed(struct qeth_qdio_out_q *queue)
  * In that case 1 is returned to inform the caller. If no buffer
  * has to be flushed, zero is returned.
  */
-static inline int
+static int
 qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
 {
        struct qeth_qdio_out_buffer *buffer;
@@ -2877,7 +2877,7 @@ qeth_switch_to_nonpacking_if_needed(struct qeth_qdio_out_q *queue)
  * Checks if there is a packing buffer and prepares it to be flushed.
  * In that case returns 1, otherwise zero.
  */
-static inline int
+static int
 qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue)
 {
        struct qeth_qdio_out_buffer *buffer;
@@ -2894,7 +2894,7 @@ qeth_flush_buffers_on_no_pci(struct qeth_qdio_out_q *queue)
        return 0;
 }
 
-static inline void
+static void
 qeth_check_outbound_queue(struct qeth_qdio_out_q *queue)
 {
        int index;
@@ -3594,7 +3594,7 @@ qeth_fake_header(struct sk_buff *skb, struct net_device *dev,
        }
 }
 
-static inline int
+static int
 qeth_send_packet(struct qeth_card *, struct sk_buff *);
 
 static int
@@ -3759,7 +3759,7 @@ qeth_stop(struct net_device *dev)
        return 0;
 }
 
-static inline int
+static int
 qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
 {
        int cast_type = RTN_UNSPEC;
@@ -3806,7 +3806,7 @@ qeth_get_cast_type(struct qeth_card *card, struct sk_buff *skb)
        return cast_type;
 }
 
-static inline int
+static int
 qeth_get_priority_queue(struct qeth_card *card, struct sk_buff *skb,
                        int ipv, int cast_type)
 {
@@ -3853,7 +3853,7 @@ qeth_get_ip_version(struct sk_buff *skb)
        }
 }
 
-static inline struct qeth_hdr *
+static struct qeth_hdr *
 __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv)
 {
 #ifdef CONFIG_QETH_VLAN
@@ -3882,14 +3882,14 @@ __qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb, int ipv)
                qeth_push_skb(card, skb, sizeof(struct qeth_hdr)));
 }
 
-static inline void
+static void
 __qeth_free_new_skb(struct sk_buff *orig_skb, struct sk_buff *new_skb)
 {
        if (orig_skb != new_skb)
                dev_kfree_skb_any(new_skb);
 }
 
-static inline struct sk_buff *
+static struct sk_buff *
 qeth_prepare_skb(struct qeth_card *card, struct sk_buff *skb,
                 struct qeth_hdr **hdr, int ipv)
 {
@@ -3940,7 +3940,7 @@ qeth_get_qeth_hdr_flags6(int cast_type)
        return ct | QETH_CAST_UNICAST;
 }
 
-static inline void
+static void
 qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr,
                            struct sk_buff *skb)
 {
@@ -3977,7 +3977,7 @@ qeth_layer2_get_packet_type(struct qeth_card *card, struct qeth_hdr *hdr,
        }
 }
 
-static inline void
+static void
 qeth_layer2_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
                        struct sk_buff *skb, int cast_type)
 {
@@ -4068,7 +4068,7 @@ qeth_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
        }
 }
 
-static inline void
+static void
 __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
                   int is_tso, int *next_element_to_fill)
 {
@@ -4112,7 +4112,7 @@ __qeth_fill_buffer(struct sk_buff *skb, struct qdio_buffer *buffer,
        *next_element_to_fill = element;
 }
 
-static inline int
+static int
 qeth_fill_buffer(struct qeth_qdio_out_q *queue,
                 struct qeth_qdio_out_buffer *buf,
                 struct sk_buff *skb)
@@ -4171,7 +4171,7 @@ qeth_fill_buffer(struct qeth_qdio_out_q *queue,
        return flush_cnt;
 }
 
-static inline int
+static int
 qeth_do_send_packet_fast(struct qeth_card *card, struct qeth_qdio_out_q *queue,
                         struct sk_buff *skb, struct qeth_hdr *hdr,
                         int elements_needed,
@@ -4222,7 +4222,7 @@ out:
        return -EBUSY;
 }
 
-static inline int
+static int
 qeth_do_send_packet(struct qeth_card *card, struct qeth_qdio_out_q *queue,
                    struct sk_buff *skb, struct qeth_hdr *hdr,
                    int elements_needed, struct qeth_eddp_context *ctx)
@@ -4328,7 +4328,7 @@ out:
        return rc;
 }
 
-static inline int
+static int
 qeth_get_elements_no(struct qeth_card *card, void *hdr,
                     struct sk_buff *skb, int elems)
 {
@@ -4349,7 +4349,7 @@ qeth_get_elements_no(struct qeth_card *card, void *hdr,
 }
 
 
-static inline int
+static int
 qeth_send_packet(struct qeth_card *card, struct sk_buff *skb)
 {
        int ipv = 0;
@@ -4536,7 +4536,7 @@ qeth_mdio_read(struct net_device *dev, int phy_id, int regnum)
 }
 
 
-static inline const char *
+static const char *
 qeth_arp_get_error_cause(int *rc)
 {
        switch (*rc) {
@@ -4597,7 +4597,7 @@ qeth_arp_set_no_entries(struct qeth_card *card, int no_entries)
        return rc;
 }
 
-static inline void
+static void
 qeth_copy_arp_entries_stripped(struct qeth_arp_query_info *qinfo,
                               struct qeth_arp_query_data *qdata,
                               int entry_size, int uentry_size)
@@ -5214,7 +5214,7 @@ qeth_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
        spin_unlock_irqrestore(&card->vlanlock, flags);
 }
 
-static inline void
+static void
 qeth_free_vlan_buffer(struct qeth_card *card, struct qeth_qdio_out_buffer *buf,
                      unsigned short vid)
 {
@@ -5625,7 +5625,7 @@ qeth_delete_mc_addresses(struct qeth_card *card)
        spin_unlock_irqrestore(&card->ip_lock, flags);
 }
 
-static inline void
+static void
 qeth_add_mc(struct qeth_card *card, struct in_device *in4_dev)
 {
        struct qeth_ipaddr *ipm;
@@ -5711,7 +5711,7 @@ qeth_layer2_add_multicast(struct qeth_card *card)
 }
 
 #ifdef CONFIG_QETH_IPV6
-static inline void
+static void
 qeth_add_mc6(struct qeth_card *card, struct inet6_dev *in6_dev)
 {
        struct qeth_ipaddr *ipm;
@@ -6022,7 +6022,7 @@ qeth_send_setdelmc(struct qeth_card *card, struct qeth_ipaddr *addr, int ipacmd)
 
        return rc;
 }
-static inline void
+static void
 qeth_fill_netmask(u8 *netmask, unsigned int len)
 {
        int i,j;
@@ -6626,7 +6626,7 @@ qeth_send_setadp_mode(struct qeth_card *card, __u32 command, __u32 mode)
        return rc;
 }
 
-static inline int
+static int
 qeth_setadapter_hstr(struct qeth_card *card)
 {
        int rc;
@@ -6889,7 +6889,7 @@ qeth_send_simple_setassparms(struct qeth_card *card,
        return rc;
 }
 
-static inline int
+static int
 qeth_start_ipa_arp_processing(struct qeth_card *card)
 {
        int rc;
@@ -7529,7 +7529,7 @@ qeth_set_allowed_threads(struct qeth_card *card, unsigned long threads,
        wake_up(&card->wait_q);
 }
 
-static inline int
+static int
 qeth_threads_running(struct qeth_card *card, unsigned long threads)
 {
        unsigned long flags;
@@ -8118,7 +8118,7 @@ qeth_del_ipato_entry(struct qeth_card *card, enum qeth_prot_versions proto,
        spin_unlock_irqrestore(&card->ip_lock, flags);
 }
 
-static inline void
+static void
 qeth_convert_addr_to_bits(u8 *addr, u8 *bits, int len)
 {
        int i, j;
index 5836737..d518419 100644 (file)
@@ -328,7 +328,7 @@ qeth_dev_bufcnt_store(struct device *dev, struct device_attribute *attr, const c
 static DEVICE_ATTR(buffer_count, 0644, qeth_dev_bufcnt_show,
                qeth_dev_bufcnt_store);
 
-static inline ssize_t
+static ssize_t
 qeth_dev_route_show(struct qeth_card *card, struct qeth_routing_info *route,
                    char *buf)
 {
@@ -368,7 +368,7 @@ qeth_dev_route4_show(struct device *dev, struct device_attribute *attr, char *bu
        return qeth_dev_route_show(card, &card->options.route4, buf);
 }
 
-static inline ssize_t
+static ssize_t
 qeth_dev_route_store(struct qeth_card *card, struct qeth_routing_info *route,
                enum qeth_prot_versions prot, const char *buf, size_t count)
 {
@@ -998,7 +998,7 @@ struct device_attribute dev_attr_##_id = {                               \
        .store  = _store,                                                    \
 };
 
-int
+static int
 qeth_check_layer2(struct qeth_card *card)
 {
        if (card->options.layer2)
@@ -1100,7 +1100,7 @@ static QETH_DEVICE_ATTR(ipato_invert4, invert4, 0644,
                        qeth_dev_ipato_invert4_show,
                        qeth_dev_ipato_invert4_store);
 
-static inline ssize_t
+static ssize_t
 qeth_dev_ipato_add_show(char *buf, struct qeth_card *card,
                        enum qeth_prot_versions proto)
 {
@@ -1146,7 +1146,7 @@ qeth_dev_ipato_add4_show(struct device *dev, struct device_attribute *attr, char
        return qeth_dev_ipato_add_show(buf, card, QETH_PROT_IPV4);
 }
 
-static inline int
+static int
 qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
                  u8 *addr, int *mask_bits)
 {
@@ -1178,7 +1178,7 @@ qeth_parse_ipatoe(const char* buf, enum qeth_prot_versions proto,
        return 0;
 }
 
-static inline ssize_t
+static ssize_t
 qeth_dev_ipato_add_store(const char *buf, size_t count,
                         struct qeth_card *card, enum qeth_prot_versions proto)
 {
@@ -1223,7 +1223,7 @@ static QETH_DEVICE_ATTR(ipato_add4, add4, 0644,
                        qeth_dev_ipato_add4_show,
                        qeth_dev_ipato_add4_store);
 
-static inline ssize_t
+static ssize_t
 qeth_dev_ipato_del_store(const char *buf, size_t count,
                         struct qeth_card *card, enum qeth_prot_versions proto)
 {
@@ -1361,7 +1361,7 @@ static struct attribute_group qeth_device_ipato_group = {
        .attrs = (struct attribute **)qeth_ipato_device_attrs,
 };
 
-static inline ssize_t
+static ssize_t
 qeth_dev_vipa_add_show(char *buf, struct qeth_card *card,
                        enum qeth_prot_versions proto)
 {
@@ -1407,7 +1407,7 @@ qeth_dev_vipa_add4_show(struct device *dev, struct device_attribute *attr, char
        return qeth_dev_vipa_add_show(buf, card, QETH_PROT_IPV4);
 }
 
-static inline int
+static int
 qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto,
                 u8 *addr)
 {
@@ -1418,7 +1418,7 @@ qeth_parse_vipae(const char* buf, enum qeth_prot_versions proto,
        return 0;
 }
 
-static inline ssize_t
+static ssize_t
 qeth_dev_vipa_add_store(const char *buf, size_t count,
                         struct qeth_card *card, enum qeth_prot_versions proto)
 {
@@ -1451,7 +1451,7 @@ static QETH_DEVICE_ATTR(vipa_add4, add4, 0644,
                        qeth_dev_vipa_add4_show,
                        qeth_dev_vipa_add4_store);
 
-static inline ssize_t
+static ssize_t
 qeth_dev_vipa_del_store(const char *buf, size_t count,
                         struct qeth_card *card, enum qeth_prot_versions proto)
 {
@@ -1542,7 +1542,7 @@ static struct attribute_group qeth_device_vipa_group = {
        .attrs = (struct attribute **)qeth_vipa_device_attrs,
 };
 
-static inline ssize_t
+static ssize_t
 qeth_dev_rxip_add_show(char *buf, struct qeth_card *card,
                       enum qeth_prot_versions proto)
 {
@@ -1588,7 +1588,7 @@ qeth_dev_rxip_add4_show(struct device *dev, struct device_attribute *attr, char
        return qeth_dev_rxip_add_show(buf, card, QETH_PROT_IPV4);
 }
 
-static inline int
+static int
 qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto,
                 u8 *addr)
 {
@@ -1599,7 +1599,7 @@ qeth_parse_rxipe(const char* buf, enum qeth_prot_versions proto,
        return 0;
 }
 
-static inline ssize_t
+static ssize_t
 qeth_dev_rxip_add_store(const char *buf, size_t count,
                        struct qeth_card *card, enum qeth_prot_versions proto)
 {
@@ -1632,7 +1632,7 @@ static QETH_DEVICE_ATTR(rxip_add4, add4, 0644,
                        qeth_dev_rxip_add4_show,
                        qeth_dev_rxip_add4_store);
 
-static inline ssize_t
+static ssize_t
 qeth_dev_rxip_del_store(const char *buf, size_t count,
                        struct qeth_card *card, enum qeth_prot_versions proto)
 {
index e088b5e..806bb1a 100644 (file)
 #include <linux/errno.h>
 #include <linux/workqueue.h>
 #include <linux/time.h>
+#include <linux/device.h>
 #include <linux/kthread.h>
-
+#include <asm/etr.h>
 #include <asm/lowcore.h>
-
+#include <asm/cio.h>
+#include "cio/cio.h"
+#include "cio/chsc.h"
+#include "cio/css.h"
 #include "s390mach.h"
 
 static struct semaphore m_sem;
 
-extern int css_process_crw(int, int);
-extern int chsc_process_crw(void);
-extern int chp_process_crw(int, int);
-extern void css_reiterate_subchannels(void);
-
-extern struct workqueue_struct *slow_path_wq;
-extern struct work_struct slow_path_work;
-
 static NORET_TYPE void
 s390_handle_damage(char *msg)
 {
@@ -470,6 +466,19 @@ s390_do_machine_check(struct pt_regs *regs)
                        s390_handle_damage("unable to revalidate registers.");
        }
 
+       if (mci->cd) {
+               /* Timing facility damage */
+               s390_handle_damage("TOD clock damaged");
+       }
+
+       if (mci->ed && mci->ec) {
+               /* External damage */
+               if (S390_lowcore.external_damage_code & (1U << ED_ETR_SYNC))
+                       etr_sync_check();
+               if (S390_lowcore.external_damage_code & (1U << ED_ETR_SWITCH))
+                       etr_switch_to_local();
+       }
+
        if (mci->se)
                /* Storage error uncorrected */
                s390_handle_damage("received storage error uncorrected "
@@ -508,7 +517,7 @@ static int
 machine_check_init(void)
 {
        init_MUTEX_LOCKED(&m_sem);
-       ctl_clear_bit(14, 25);  /* disable external damage MCH */
+       ctl_set_bit(14, 25);    /* enable external damage MCH */
        ctl_set_bit(14, 27);    /* enable system recovery MCH */
 #ifdef CONFIG_MACHCHK_WARNING
        ctl_set_bit(14, 24);    /* enable warning MCH */
@@ -529,7 +538,11 @@ arch_initcall(machine_check_init);
 static int __init
 machine_check_crw_init (void)
 {
-       kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
+       struct task_struct *task;
+
+       task = kthread_run(s390_collect_crw_info, &m_sem, "kmcheck");
+       if (IS_ERR(task))
+               return PTR_ERR(task);
        ctl_set_bit(14, 28);    /* enable channel report MCH */
        return 0;
 }
index 7abb42a..d3ca428 100644 (file)
@@ -102,4 +102,7 @@ static inline int stcrw(struct crw *pcrw )
        return ccode;
 }
 
+#define ED_ETR_SYNC    12      /* External damage ETR sync check */
+#define ED_ETR_SWITCH  13      /* External damage ETR switch to local */
+
 #endif /* __s390mach */
index 85093b7..39a8852 100644 (file)
@@ -47,13 +47,12 @@ static int __init  zfcp_module_init(void);
 static void zfcp_ns_gid_pn_handler(unsigned long);
 
 /* miscellaneous */
-static inline int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
-static inline void zfcp_sg_list_free(struct zfcp_sg_list *);
-static inline int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,
-                                             void __user *, size_t);
-static inline int zfcp_sg_list_copy_to_user(void __user *,
-                                           struct zfcp_sg_list *, size_t);
-
+static int zfcp_sg_list_alloc(struct zfcp_sg_list *, size_t);
+static void zfcp_sg_list_free(struct zfcp_sg_list *);
+static int zfcp_sg_list_copy_from_user(struct zfcp_sg_list *,
+                                      void __user *, size_t);
+static int zfcp_sg_list_copy_to_user(void __user *,
+                                    struct zfcp_sg_list *, size_t);
 static long zfcp_cfdc_dev_ioctl(struct file *, unsigned int, unsigned long);
 
 #define ZFCP_CFDC_IOC_MAGIC                     0xDD
@@ -605,7 +604,7 @@ zfcp_cfdc_dev_ioctl(struct file *file, unsigned int command,
  * elements of the scatter-gather list. The maximum size of a single element
  * in the scatter-gather list is PAGE_SIZE.
  */
-static inline int
+static int
 zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
 {
        struct scatterlist *sg;
@@ -652,7 +651,7 @@ zfcp_sg_list_alloc(struct zfcp_sg_list *sg_list, size_t size)
  * Memory for each element in the scatter-gather list is freed.
  * Finally sg_list->sg is freed itself and sg_list->count is reset.
  */
-static inline void
+static void
 zfcp_sg_list_free(struct zfcp_sg_list *sg_list)
 {
        struct scatterlist *sg;
@@ -697,7 +696,7 @@ zfcp_sg_size(struct scatterlist *sg, unsigned int sg_count)
  * @size: number of bytes to be copied
  * Return: 0 on success, -EFAULT if copy_from_user fails.
  */
-static inline int
+static int
 zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list,
                            void __user *user_buffer,
                             size_t size)
@@ -735,7 +734,7 @@ zfcp_sg_list_copy_from_user(struct zfcp_sg_list *sg_list,
  * @size: number of bytes to be copied
  * Return: 0 on success, -EFAULT if copy_to_user fails
  */
-static inline int
+static int
 zfcp_sg_list_copy_to_user(void __user  *user_buffer,
                          struct zfcp_sg_list *sg_list,
                           size_t size)
@@ -1799,7 +1798,7 @@ static const struct zfcp_rc_entry zfcp_p_rjt_rc[] = {
  * @code: reason code
  * @rc_table: table of reason codes and descriptions
  */
-static inline const char *
+static const char *
 zfcp_rc_description(u8 code, const struct zfcp_rc_entry *rc_table)
 {
        const char *descr = "unknown reason code";
@@ -1847,7 +1846,7 @@ zfcp_check_ct_response(struct ct_hdr *rjt)
  * @rjt_par: reject parameter acc. to FC-PH/FC-FS
  * @rc_table: table of reason codes and descriptions
  */
-static inline void
+static void
 zfcp_print_els_rjt(struct zfcp_ls_rjt_par *rjt_par,
                   const struct zfcp_rc_entry *rc_table)
 {
index 0aa3b1a..d8191d1 100644 (file)
@@ -31,7 +31,7 @@ MODULE_PARM_DESC(dbfsize,
 
 #define ZFCP_LOG_AREA                  ZFCP_LOG_AREA_OTHER
 
-static inline int
+static int
 zfcp_dbf_stck(char *out_buf, const char *label, unsigned long long stck)
 {
        unsigned long long sec;
@@ -106,7 +106,7 @@ zfcp_dbf_view_dump(char *out_buf, const char *label,
        return len;
 }
 
-static inline int
+static int
 zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area,
                     debug_entry_t * entry, char *out_buf)
 {
@@ -130,7 +130,7 @@ zfcp_dbf_view_header(debug_info_t * id, struct debug_view *view, int area,
        return len;
 }
 
-inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
 {
        struct zfcp_adapter *adapter = fsf_req->adapter;
        struct fsf_qtcb *qtcb = fsf_req->qtcb;
@@ -241,7 +241,7 @@ inline void zfcp_hba_dbf_event_fsf_response(struct zfcp_fsf_req *fsf_req)
        spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
 }
 
-inline void
+void
 zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter,
                             struct fsf_status_read_buffer *status_buffer)
 {
@@ -295,7 +295,7 @@ zfcp_hba_dbf_event_fsf_unsol(const char *tag, struct zfcp_adapter *adapter,
        spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
 }
 
-inline void
+void
 zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status,
                        unsigned int qdio_error, unsigned int siga_error,
                        int sbal_index, int sbal_count)
@@ -316,7 +316,7 @@ zfcp_hba_dbf_event_qdio(struct zfcp_adapter *adapter, unsigned int status,
        spin_unlock_irqrestore(&adapter->hba_dbf_lock, flags);
 }
 
-static inline int
+static int
 zfcp_hba_dbf_view_response(char *out_buf,
                           struct zfcp_hba_dbf_record_response *rec)
 {
@@ -403,7 +403,7 @@ zfcp_hba_dbf_view_response(char *out_buf,
        return len;
 }
 
-static inline int
+static int
 zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec)
 {
        int len = 0;
@@ -424,7 +424,7 @@ zfcp_hba_dbf_view_status(char *out_buf, struct zfcp_hba_dbf_record_status *rec)
        return len;
 }
 
-static inline int
+static int
 zfcp_hba_dbf_view_qdio(char *out_buf, struct zfcp_hba_dbf_record_qdio *rec)
 {
        int len = 0;
@@ -469,7 +469,7 @@ zfcp_hba_dbf_view_format(debug_info_t * id, struct debug_view *view,
        return len;
 }
 
-struct debug_view zfcp_hba_dbf_view = {
+static struct debug_view zfcp_hba_dbf_view = {
        "structured",
        NULL,
        &zfcp_dbf_view_header,
@@ -478,7 +478,7 @@ struct debug_view zfcp_hba_dbf_view = {
        NULL
 };
 
-inline void
+void
 _zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req,
                              u32 s_id, u32 d_id, void *buffer, int buflen)
 {
@@ -519,7 +519,7 @@ _zfcp_san_dbf_event_common_ct(const char *tag, struct zfcp_fsf_req *fsf_req,
        spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
 }
 
-inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
 {
        struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
        struct zfcp_port *port = ct->port;
@@ -531,7 +531,7 @@ inline void zfcp_san_dbf_event_ct_request(struct zfcp_fsf_req *fsf_req)
                                      ct->req->length);
 }
 
-inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
 {
        struct zfcp_send_ct *ct = (struct zfcp_send_ct *)fsf_req->data;
        struct zfcp_port *port = ct->port;
@@ -543,7 +543,7 @@ inline void zfcp_san_dbf_event_ct_response(struct zfcp_fsf_req *fsf_req)
                                      ct->resp->length);
 }
 
-static inline void
+static void
 _zfcp_san_dbf_event_common_els(const char *tag, int level,
                               struct zfcp_fsf_req *fsf_req, u32 s_id,
                               u32 d_id, u8 ls_code, void *buffer, int buflen)
@@ -585,7 +585,7 @@ _zfcp_san_dbf_event_common_els(const char *tag, int level,
        spin_unlock_irqrestore(&adapter->san_dbf_lock, flags);
 }
 
-inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
 {
        struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
 
@@ -597,7 +597,7 @@ inline void zfcp_san_dbf_event_els_request(struct zfcp_fsf_req *fsf_req)
                                       els->req->length);
 }
 
-inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
 {
        struct zfcp_send_els *els = (struct zfcp_send_els *)fsf_req->data;
 
@@ -608,7 +608,7 @@ inline void zfcp_san_dbf_event_els_response(struct zfcp_fsf_req *fsf_req)
                                       els->resp->length);
 }
 
-inline void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req)
+void zfcp_san_dbf_event_incoming_els(struct zfcp_fsf_req *fsf_req)
 {
        struct zfcp_adapter *adapter = fsf_req->adapter;
        struct fsf_status_read_buffer *status_buffer =
@@ -693,7 +693,7 @@ zfcp_san_dbf_view_format(debug_info_t * id, struct debug_view *view,
        return len;
 }
 
-struct debug_view zfcp_san_dbf_view = {
+static struct debug_view zfcp_san_dbf_view = {
        "structured",
        NULL,
        &zfcp_dbf_view_header,
@@ -702,7 +702,7 @@ struct debug_view zfcp_san_dbf_view = {
        NULL
 };
 
-static inline void
+static void
 _zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level,
                            struct zfcp_adapter *adapter,
                            struct scsi_cmnd *scsi_cmnd,
@@ -786,7 +786,7 @@ _zfcp_scsi_dbf_event_common(const char *tag, const char *tag2, int level,
        spin_unlock_irqrestore(&adapter->scsi_dbf_lock, flags);
 }
 
-inline void
+void
 zfcp_scsi_dbf_event_result(const char *tag, int level,
                           struct zfcp_adapter *adapter,
                           struct scsi_cmnd *scsi_cmnd,
@@ -796,7 +796,7 @@ zfcp_scsi_dbf_event_result(const char *tag, int level,
                        adapter, scsi_cmnd, fsf_req, 0);
 }
 
-inline void
+void
 zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter,
                          struct scsi_cmnd *scsi_cmnd,
                          struct zfcp_fsf_req *new_fsf_req,
@@ -806,7 +806,7 @@ zfcp_scsi_dbf_event_abort(const char *tag, struct zfcp_adapter *adapter,
                        adapter, scsi_cmnd, new_fsf_req, old_req_id);
 }
 
-inline void
+void
 zfcp_scsi_dbf_event_devreset(const char *tag, u8 flag, struct zfcp_unit *unit,
                             struct scsi_cmnd *scsi_cmnd)
 {
@@ -884,7 +884,7 @@ zfcp_scsi_dbf_view_format(debug_info_t * id, struct debug_view *view,
        return len;
 }
 
-struct debug_view zfcp_scsi_dbf_view = {
+static struct debug_view zfcp_scsi_dbf_view = {
        "structured",
        NULL,
        &zfcp_dbf_view_header,
index c88babc..88642de 100644 (file)
@@ -200,7 +200,7 @@ void zfcp_fsf_start_timer(struct zfcp_fsf_req *fsf_req, unsigned long timeout)
  * returns:    0       - initiated action successfully
  *             <0      - failed to initiate action
  */
-int
+static int
 zfcp_erp_adapter_reopen_internal(struct zfcp_adapter *adapter, int clear_mask)
 {
        int retval;
@@ -295,7 +295,7 @@ zfcp_erp_unit_shutdown(struct zfcp_unit *unit, int clear_mask)
  * zfcp_erp_adisc - send ADISC ELS command
  * @port: port structure
  */
-int
+static int
 zfcp_erp_adisc(struct zfcp_port *port)
 {
        struct zfcp_adapter *adapter = port->adapter;
@@ -380,7 +380,7 @@ zfcp_erp_adisc(struct zfcp_port *port)
  *
  * If ADISC failed (LS_RJT or timed out) forced reopen of the port is triggered.
  */
-void
+static void
 zfcp_erp_adisc_handler(unsigned long data)
 {
        struct zfcp_send_els *send_els;
@@ -3141,7 +3141,6 @@ zfcp_erp_action_cleanup(int action, struct zfcp_adapter *adapter,
                break;
        case ZFCP_ERP_ACTION_REOPEN_ADAPTER:
                if (result != ZFCP_ERP_SUCCEEDED) {
-                       struct zfcp_port *port;
                        list_for_each_entry(port, &adapter->port_list_head, list)
                                if (port->rport &&
                                    !atomic_test_mask(ZFCP_STATUS_PORT_WKA,
index b8794d7..cda0cc0 100644 (file)
@@ -119,8 +119,8 @@ extern int  zfcp_adapter_scsi_register(struct zfcp_adapter *);
 extern void zfcp_adapter_scsi_unregister(struct zfcp_adapter *);
 extern void zfcp_set_fcp_dl(struct fcp_cmnd_iu *, fcp_dl_t);
 extern char *zfcp_get_fcp_rsp_info_ptr(struct fcp_rsp_iu *);
-extern void set_host_byte(u32 *, char);
-extern void set_driver_byte(u32 *, char);
+extern void set_host_byte(int *, char);
+extern void set_driver_byte(int *, char);
 extern char *zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *);
 extern fcp_dl_t zfcp_get_fcp_dl(struct fcp_cmnd_iu *);
 
index 067f151..4b3ae3f 100644 (file)
@@ -4563,7 +4563,7 @@ zfcp_fsf_req_sbal_check(unsigned long *flags,
 /*
  * set qtcb pointer in fsf_req and initialize QTCB
  */
-static inline void
+static void
 zfcp_fsf_req_qtcb_init(struct zfcp_fsf_req *fsf_req)
 {
        if (likely(fsf_req->qtcb != NULL)) {
index dbd9f48..1e12a78 100644 (file)
 
 #include "zfcp_ext.h"
 
-static inline void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
+static void zfcp_qdio_sbal_limit(struct zfcp_fsf_req *, int);
 static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_get
        (struct zfcp_qdio_queue *, int, int);
 static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_resp
        (struct zfcp_fsf_req *, int, int);
-static inline volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
+static volatile struct qdio_buffer_element *zfcp_qdio_sbal_chain
        (struct zfcp_fsf_req *, unsigned long);
-static inline volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
+static volatile struct qdio_buffer_element *zfcp_qdio_sbale_next
        (struct zfcp_fsf_req *, unsigned long);
-static inline int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
+static int zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *, int, int);
 static inline int zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *);
-static inline void zfcp_qdio_sbale_fill
+static void zfcp_qdio_sbale_fill
        (struct zfcp_fsf_req *, unsigned long, void *, int);
-static inline int zfcp_qdio_sbals_from_segment
+static int zfcp_qdio_sbals_from_segment
        (struct zfcp_fsf_req *, unsigned long, void *, unsigned long);
-static inline int zfcp_qdio_sbals_from_buffer
+static int zfcp_qdio_sbals_from_buffer
        (struct zfcp_fsf_req *, unsigned long, void *, unsigned long, int);
 
 static qdio_handler_t zfcp_qdio_request_handler;
@@ -201,7 +201,7 @@ zfcp_qdio_allocate(struct zfcp_adapter *adapter)
  * returns:    error flag
  *
  */
-static inline int
+static int
 zfcp_qdio_handler_error_check(struct zfcp_adapter *adapter, unsigned int status,
                              unsigned int qdio_error, unsigned int siga_error,
                              int first_element, int elements_processed)
@@ -462,7 +462,7 @@ zfcp_qdio_sbale_get(struct zfcp_qdio_queue *queue, int sbal, int sbale)
  * zfcp_qdio_sbale_req - return pointer to SBALE of request_queue for
  *     a struct zfcp_fsf_req
  */
-inline volatile struct qdio_buffer_element *
+volatile struct qdio_buffer_element *
 zfcp_qdio_sbale_req(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
 {
        return zfcp_qdio_sbale_get(&fsf_req->adapter->request_queue,
@@ -484,7 +484,7 @@ zfcp_qdio_sbale_resp(struct zfcp_fsf_req *fsf_req, int sbal, int sbale)
  * zfcp_qdio_sbale_curr - return current SBALE on request_queue for
  *     a struct zfcp_fsf_req
  */
-inline volatile struct qdio_buffer_element *
+volatile struct qdio_buffer_element *
 zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req)
 {
        return zfcp_qdio_sbale_req(fsf_req, fsf_req->sbal_curr,
@@ -499,7 +499,7 @@ zfcp_qdio_sbale_curr(struct zfcp_fsf_req *fsf_req)
  *
  * Note: We can assume at least one free SBAL in the request_queue when called.
  */
-static inline void
+static void
 zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
 {
        int count = atomic_read(&fsf_req->adapter->request_queue.free_count);
@@ -517,7 +517,7 @@ zfcp_qdio_sbal_limit(struct zfcp_fsf_req *fsf_req, int max_sbals)
  *
  * This function changes sbal_curr, sbale_curr, sbal_number of fsf_req.
  */
-static inline volatile struct qdio_buffer_element *
+static volatile struct qdio_buffer_element *
 zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
 {
        volatile struct qdio_buffer_element *sbale;
@@ -554,7 +554,7 @@ zfcp_qdio_sbal_chain(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
 /**
  * zfcp_qdio_sbale_next - switch to next SBALE, chain SBALs if needed
  */
-static inline volatile struct qdio_buffer_element *
+static volatile struct qdio_buffer_element *
 zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
 {
        if (fsf_req->sbale_curr == ZFCP_LAST_SBALE_PER_SBAL)
@@ -569,7 +569,7 @@ zfcp_qdio_sbale_next(struct zfcp_fsf_req *fsf_req, unsigned long sbtype)
  * zfcp_qdio_sbals_zero - initialize SBALs between first and last in queue
  *     with zero from
  */
-static inline int
+static int
 zfcp_qdio_sbals_zero(struct zfcp_qdio_queue *queue, int first, int last)
 {
        struct qdio_buffer **buf = queue->buffer;
@@ -603,7 +603,7 @@ zfcp_qdio_sbals_wipe(struct zfcp_fsf_req *fsf_req)
  * zfcp_qdio_sbale_fill - set address and lenght in current SBALE
  *     on request_queue
  */
-static inline void
+static void
 zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
                     void *addr, int length)
 {
@@ -624,7 +624,7 @@ zfcp_qdio_sbale_fill(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
  * Alignment and length of the segment determine how many SBALEs are needed
  * for the memory segment.
  */
-static inline int
+static int
 zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
                             void *start_addr, unsigned long total_length)
 {
@@ -659,7 +659,7 @@ zfcp_qdio_sbals_from_segment(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
  * @sg_count: number of elements in scatter-gather list
  * @max_sbals: upper bound for number of SBALs to be used
  */
-inline int
+int
 zfcp_qdio_sbals_from_sg(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
                         struct scatterlist *sg,        int sg_count, int max_sbals)
 {
@@ -707,7 +707,7 @@ out:
  * @length: length of buffer
  * @max_sbals: upper bound for number of SBALs to be used
  */
-static inline int
+static int
 zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
                            void *buffer, unsigned long length, int max_sbals)
 {
@@ -728,7 +728,7 @@ zfcp_qdio_sbals_from_buffer(struct zfcp_fsf_req *fsf_req, unsigned long sbtype,
  * @scsi_cmnd: either scatter-gather list or buffer contained herein is used
  *     to fill SBALs
  */
-inline int
+int
 zfcp_qdio_sbals_from_scsicmnd(struct zfcp_fsf_req *fsf_req,
                              unsigned long sbtype, struct scsi_cmnd *scsi_cmnd)
 {
index 452d96f..99db020 100644 (file)
@@ -90,7 +90,7 @@ zfcp_get_fcp_sns_info_ptr(struct fcp_rsp_iu *fcp_rsp_iu)
        return fcp_sns_info_ptr;
 }
 
-fcp_dl_t *
+static fcp_dl_t *
 zfcp_get_fcp_dl_ptr(struct fcp_cmnd_iu * fcp_cmd)
 {
        int additional_length = fcp_cmd->add_fcp_cdb_length << 2;
@@ -124,19 +124,19 @@ zfcp_set_fcp_dl(struct fcp_cmnd_iu *fcp_cmd, fcp_dl_t fcp_dl)
  * regarding the specified byte
  */
 static inline void
-set_byte(u32 * result, char status, char pos)
+set_byte(int *result, char status, char pos)
 {
        *result |= status << (pos * 8);
 }
 
 void
-set_host_byte(u32 * result, char status)
+set_host_byte(int *result, char status)
 {
        set_byte(result, status, 2);
 }
 
 void
-set_driver_byte(u32 * result, char status)
+set_driver_byte(int *result, char status)
 {
        set_byte(result, status, 3);
 }
@@ -280,7 +280,7 @@ out:
        return retval;
 }
 
-void
+static void
 zfcp_scsi_command_sync_handler(struct scsi_cmnd *scpnt)
 {
        struct completion *wait = (struct completion *) scpnt->SCp.ptr;
@@ -324,7 +324,7 @@ zfcp_scsi_command_sync(struct zfcp_unit *unit, struct scsi_cmnd *scpnt,
  * returns:    0 - success, SCSI command enqueued
  *             !0 - failure
  */
-int
+static int
 zfcp_scsi_queuecommand(struct scsi_cmnd *scpnt,
                       void (*done) (struct scsi_cmnd *))
 {
@@ -380,7 +380,7 @@ zfcp_unit_lookup(struct zfcp_adapter *adapter, int channel, unsigned int id,
  * will handle late commands.  (Usually, the normal completion of late
  * commands is ignored with respect to the running abort operation.)
  */
-int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
+static int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
 {
        struct Scsi_Host *scsi_host;
        struct zfcp_adapter *adapter;
@@ -445,7 +445,7 @@ int zfcp_scsi_eh_abort_handler(struct scsi_cmnd *scpnt)
        return retval;
 }
 
-int
+static int
 zfcp_scsi_eh_device_reset_handler(struct scsi_cmnd *scpnt)
 {
        int retval;
@@ -541,7 +541,7 @@ zfcp_task_management_function(struct zfcp_unit *unit, u8 tm_flags,
 /**
  * zfcp_scsi_eh_host_reset_handler - handler for host and bus reset
  */
-int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
+static int zfcp_scsi_eh_host_reset_handler(struct scsi_cmnd *scpnt)
 {
        struct zfcp_unit *unit;
        struct zfcp_adapter *adapter;
index 1e788e8..090743d 100644 (file)
@@ -9,8 +9,14 @@
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <asm/ebcdic.h>
 
+/* Sigh, math-emu. Don't ask. */
+#include <asm/sfp-util.h>
+#include <math-emu/soft-fp.h>
+#include <math-emu/single.h>
+
 struct sysinfo_1_1_1 {
        char reserved_0[32];
        char manufacturer[16];
@@ -198,7 +204,7 @@ static int stsi_1_2_2(struct sysinfo_1_2_2 *info, char *page, int len)
                 * if the higher order 8 bits are not zero. Printing
                 * a floating point number in the kernel is a no-no,
                 * always print the number as 32 bit unsigned integer.
-                * The user-space needs to know about the stange
+                * The user-space needs to know about the strange
                 * encoding of the alternate cpu capability.
                 */
                len += sprintf(page + len, "Capability:           %u %u\n",
@@ -351,3 +357,58 @@ static __init int create_proc_sysinfo(void)
 
 __initcall(create_proc_sysinfo);
 
+/*
+ * CPU capability might have changed. Therefore recalculate loops_per_jiffy.
+ */
+void s390_adjust_jiffies(void)
+{
+       struct sysinfo_1_2_2 *info;
+       const unsigned int fmil = 0x4b189680;   /* 1e7 as 32-bit float. */
+       FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
+       FP_DECL_EX;
+       unsigned int capability;
+
+       info = (void *) get_zeroed_page(GFP_KERNEL);
+       if (!info)
+               return;
+
+       if (stsi(info, 1, 2, 2) != -ENOSYS) {
+               /*
+                * Major sigh. The cpu capability encoding is "special".
+                * If the first 9 bits of info->capability are 0 then it
+                * is a 32 bit unsigned integer in the range 0 .. 2^23.
+                * If the first 9 bits are != 0 then it is a 32 bit float.
+                * In addition a lower value indicates a proportionally
+                * higher cpu capacity. Bogomips are the other way round.
+                * To get to a halfway suitable number we divide 1e7
+                * by the cpu capability number. Yes, that means a floating
+                * point division .. math-emu here we come :-)
+                */
+               FP_UNPACK_SP(SA, &fmil);
+               if ((info->capability >> 23) == 0)
+                       FP_FROM_INT_S(SB, info->capability, 32, int);
+               else
+                       FP_UNPACK_SP(SB, &info->capability);
+               FP_DIV_S(SR, SA, SB);
+               FP_TO_INT_S(capability, SR, 32, 0);
+       } else
+               /*
+                * Really old machine without stsi block for basic
+                * cpu information. Report 42.0 bogomips.
+                */
+               capability = 42;
+       loops_per_jiffy = capability * (500000/HZ);
+       free_page((unsigned long) info);
+}
+
+/*
+ * calibrate the delay loop
+ */
+void __init calibrate_delay(void)
+{
+       s390_adjust_jiffies();
+       /* Print the good old Bogomips line .. */
+       printk(KERN_DEBUG "Calibrating delay loop (skipped)... "
+              "%lu.%02lu BogoMIPS preset\n", loops_per_jiffy/(500000/HZ),
+              (loops_per_jiffy/(5000/HZ)) % 100);
+}
index b318500..821386c 100644 (file)
@@ -7558,9 +7558,6 @@ static struct pci_device_id ipr_pci_table[] __devinitdata = {
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_575C,
              0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
-       { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN,
-             PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B8,
-             0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
        { PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_OBSIDIAN_E,
              PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_57B7,
              0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
index 8b41f9c..dccdc50 100644 (file)
@@ -1234,7 +1234,7 @@ static int init_queue(struct driver_data *drv_data)
 
        INIT_WORK(&drv_data->pump_messages, pump_messages);
        drv_data->workqueue = create_singlethread_workqueue(
-                                       drv_data->master->cdev.dev->bus_id);
+                                       drv_data->master->dev.parent->bus_id);
        if (drv_data->workqueue == NULL)
                return -EBUSY;
 
index 6307428..35d8c01 100644 (file)
@@ -193,7 +193,7 @@ 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;
+       struct device           *dev = &master->dev;
        int                     status;
 
        /* NOTE:  caller did any chip->bus_num checks necessary */
@@ -215,7 +215,7 @@ spi_new_device(struct spi_master *master, struct spi_board_info *chip)
        proxy->modalias = chip->modalias;
 
        snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,
-                       "%s.%u", master->cdev.class_id,
+                       "%s.%u", master->dev.bus_id,
                        chip->chip_select);
        proxy->dev.parent = dev;
        proxy->dev.bus = &spi_bus_type;
@@ -290,7 +290,7 @@ static void __init_or_module
 scan_boardinfo(struct spi_master *master)
 {
        struct boardinfo        *bi;
-       struct device           *dev = master->cdev.dev;
+       struct device           *dev = master->dev.parent;
 
        down(&board_lock);
        list_for_each_entry(bi, &board_list, list) {
@@ -319,18 +319,18 @@ scan_boardinfo(struct spi_master *master)
 
 /*-------------------------------------------------------------------------*/
 
-static void spi_master_release(struct class_device *cdev)
+static void spi_master_release(struct device *dev)
 {
        struct spi_master *master;
 
-       master = container_of(cdev, struct spi_master, cdev);
+       master = container_of(dev, struct spi_master, dev);
        kfree(master);
 }
 
 static struct class spi_master_class = {
        .name           = "spi_master",
        .owner          = THIS_MODULE,
-       .release        = spi_master_release,
+       .dev_release    = spi_master_release,
 };
 
 
@@ -364,9 +364,9 @@ spi_alloc_master(struct device *dev, unsigned size)
        if (!master)
                return NULL;
 
-       class_device_initialize(&master->cdev);
-       master->cdev.class = &spi_master_class;
-       master->cdev.dev = get_device(dev);
+       device_initialize(&master->dev);
+       master->dev.class = &spi_master_class;
+       master->dev.parent = get_device(dev);
        spi_master_set_devdata(master, &master[1]);
 
        return master;
@@ -396,7 +396,7 @@ int __init_or_module
 spi_register_master(struct spi_master *master)
 {
        static atomic_t         dyn_bus_id = ATOMIC_INIT((1<<16) - 1);
-       struct device           *dev = master->cdev.dev;
+       struct device           *dev = master->dev.parent;
        int                     status = -ENODEV;
        int                     dynamic = 0;
 
@@ -412,12 +412,12 @@ spi_register_master(struct spi_master *master)
        /* 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,
+       snprintf(master->dev.bus_id, sizeof master->dev.bus_id,
                "spi%u", master->bus_num);
-       status = class_device_add(&master->cdev);
+       status = device_add(&master->dev);
        if (status < 0)
                goto done;
-       dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id,
+       dev_dbg(dev, "registered master %s%s\n", master->dev.bus_id,
                        dynamic ? " (dynamic)" : "");
 
        /* populate children from any spi device tables */
@@ -449,8 +449,8 @@ void spi_unregister_master(struct spi_master *master)
 {
        int dummy;
 
-       dummy = device_for_each_child(master->cdev.dev, NULL, __unregister);
-       class_device_unregister(&master->cdev);
+       dummy = device_for_each_child(&master->dev, NULL, __unregister);
+       device_unregister(&master->dev);
 }
 EXPORT_SYMBOL_GPL(spi_unregister_master);
 
@@ -471,7 +471,7 @@ struct spi_master *spi_busnum_to_master(u16 bus_num)
 
        down(&spi_master_class.sem);
        list_for_each_entry(cdev, &spi_master_class.children, node) {
-               m = container_of(cdev, struct spi_master, cdev);
+               m = container_of(cdev, struct spi_master, dev.kobj);
                if (m->bus_num == bus_num) {
                        master = spi_master_get(m);
                        break;
index 57289b6..4638e6c 100644 (file)
@@ -479,7 +479,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang)
        /* 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);
+                       bitbang->master->dev.parent->bus_id);
        if (bitbang->workqueue == NULL) {
                status = -EBUSY;
                goto err1;
@@ -513,14 +513,14 @@ int spi_bitbang_stop(struct spi_bitbang *bitbang)
        while (!list_empty(&bitbang->queue) && limit--) {
                spin_unlock_irq(&bitbang->lock);
 
-               dev_dbg(bitbang->master->cdev.dev, "wait for queue\n");
+               dev_dbg(&bitbang->master->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");
+               dev_err(&bitbang->master->dev, "queue didn't empty\n");
                return -EBUSY;
        }
 
index 312987a..31b7970 100644 (file)
@@ -246,7 +246,7 @@ static void butterfly_attach(struct parport *p)
         * and no way to be selective about what it binds to.
         */
 
-       /* FIXME where should master->cdev.dev come from?
+       /* FIXME where should master->dev.parent come from?
         * e.g. /sys/bus/pnp0/00:0b, some PCI thing, etc
         * setting up a platform device like this is an ugly kluge...
         */
@@ -386,7 +386,7 @@ static void butterfly_detach(struct parport *p)
        butterfly = NULL;
 
        /* stop() unregisters child devices too */
-       pdev = to_platform_device(pp->bitbang.master->cdev.dev);
+       pdev = to_platform_device(pp->bitbang.master->dev.parent);
        status = spi_bitbang_stop(&pp->bitbang);
 
        /* turn off VCC */
index 8ed6c75..638b800 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/stat.h>
 #include <linux/timer.h>
 #include <linux/types.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/workqueue.h>
 
 #include "usbatm.h"
index 6377db1..63e50a1 100644 (file)
@@ -398,6 +398,9 @@ static int usblp_open(struct inode *inode, struct file *file)
        retval = 0;
 #endif
 
+       retval = usb_autopm_get_interface(intf);
+       if (retval < 0)
+               goto out;
        usblp->used = 1;
        file->private_data = usblp;
 
@@ -442,6 +445,7 @@ static int usblp_release(struct inode *inode, struct file *file)
        usblp->used = 0;
        if (usblp->present) {
                usblp_unlink_urbs(usblp);
+               usb_autopm_put_interface(usblp->intf);
        } else          /* finish cleanup from disconnect */
                usblp_cleanup (usblp);
        mutex_unlock (&usblp_mutex);
@@ -1203,14 +1207,9 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
 {
        struct usblp *usblp = usb_get_intfdata (intf);
 
-       /* this races against normal access and open */
-       mutex_lock (&usblp_mutex);
-       mutex_lock (&usblp->mut);
        /* we take no more IO */
        usblp->sleeping = 1;
        usblp_unlink_urbs(usblp);
-       mutex_unlock (&usblp->mut);
-       mutex_unlock (&usblp_mutex);
 
        return 0;
 }
@@ -1220,15 +1219,9 @@ static int usblp_resume (struct usb_interface *intf)
        struct usblp *usblp = usb_get_intfdata (intf);
        int r;
 
-       mutex_lock (&usblp_mutex);
-       mutex_lock (&usblp->mut);
-
        usblp->sleeping = 0;
        r = handle_bidir (usblp);
 
-       mutex_unlock (&usblp->mut);
-       mutex_unlock (&usblp_mutex);
-
        return r;
 }
 
@@ -1251,6 +1244,7 @@ static struct usb_driver usblp_driver = {
        .suspend =      usblp_suspend,
        .resume =       usblp_resume,
        .id_table =     usblp_ids,
+       .supports_autosuspend = 1,
 };
 
 static int __init usblp_init(void)
index 3e66b2a..2fc0f88 100644 (file)
@@ -33,19 +33,6 @@ config USB_DEVICEFS
 
          Most users want to say Y here.
 
-config USB_BANDWIDTH
-       bool "Enforce USB bandwidth allocation (EXPERIMENTAL)"
-       depends on USB && EXPERIMENTAL
-       help
-         If you say Y here, the USB subsystem enforces USB bandwidth
-         allocation and will prevent some device opens from succeeding
-         if they would cause USB bandwidth usage to go above 90% of
-         the bus bandwidth.
-
-         If you say N here, these conditions will cause warning messages
-         about USB bandwidth usage to be logged and some devices or
-         drivers may not work correctly.
-
 config USB_DYNAMIC_MINORS
        bool "Dynamic USB minor allocation (EXPERIMENTAL)"
        depends on USB && EXPERIMENTAL
index c3915dc..ead2475 100644 (file)
@@ -49,9 +49,9 @@ static const size_t   pool_max [HCD_BUFFER_POOLS] = {
  *
  * Call hcd_buffer_destroy() to clean up after using those pools.
  */
-int hcd_buffer_create (struct usb_hcd *hcd)
+int hcd_buffer_create(struct usb_hcd *hcd)
 {
-       char            name [16];
+       char            name[16];
        int             i, size;
 
        if (!hcd->self.controller->dma_mask)
@@ -60,11 +60,11 @@ int hcd_buffer_create (struct usb_hcd *hcd)
        for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
                if (!(size = pool_max [i]))
                        continue;
-               snprintf (name, sizeof name, "buffer-%d", size);
-               hcd->pool [i] = dma_pool_create (name, hcd->self.controller,
+               snprintf(name, sizeof name, "buffer-%d", size);
+               hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
                                size, size, 0);
                if (!hcd->pool [i]) {
-                       hcd_buffer_destroy (hcd);
+                       hcd_buffer_destroy(hcd);
                        return -ENOMEM;
                }
        }
@@ -79,14 +79,14 @@ int hcd_buffer_create (struct usb_hcd *hcd)
  *
  * This frees the buffer pools created by hcd_buffer_create().
  */
-void hcd_buffer_destroy (struct usb_hcd *hcd)
+void hcd_buffer_destroy(struct usb_hcd *hcd)
 {
        int             i;
 
        for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
-               struct dma_pool         *pool = hcd->pool [i];
+               struct dma_pool         *pool = hcd->pool[i];
                if (pool) {
-                       dma_pool_destroy (pool);
+                       dma_pool_destroy(pool);
                        hcd->pool[i] = NULL;
                }
        }
@@ -97,8 +97,8 @@ void hcd_buffer_destroy (struct usb_hcd *hcd)
  * better sharing and to leverage mm/slab.c intelligence.
  */
 
-void *hcd_buffer_alloc (
-       struct usb_bus          *bus,
+void *hcd_buffer_alloc(
+       struct usb_bus  *bus,
        size_t                  size,
        gfp_t                   mem_flags,
        dma_addr_t              *dma
@@ -110,18 +110,18 @@ void *hcd_buffer_alloc (
        /* some USB hosts just use PIO */
        if (!bus->controller->dma_mask) {
                *dma = ~(dma_addr_t) 0;
-               return kmalloc (size, mem_flags);
+               return kmalloc(size, mem_flags);
        }
 
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
                if (size <= pool_max [i])
-                       return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
+                       return dma_pool_alloc(hcd->pool [i], mem_flags, dma);
        }
-       return dma_alloc_coherent (hcd->self.controller, size, dma, 0);
+       return dma_alloc_coherent(hcd->self.controller, size, dma, 0);
 }
 
-void hcd_buffer_free (
-       struct usb_bus          *bus,
+void hcd_buffer_free(
+       struct usb_bus  *bus,
        size_t                  size,
        void                    *addr,
        dma_addr_t              dma
@@ -134,15 +134,15 @@ void hcd_buffer_free (
                return;
 
        if (!bus->controller->dma_mask) {
-               kfree (addr);
+               kfree(addr);
                return;
        }
 
        for (i = 0; i < HCD_BUFFER_POOLS; i++) {
                if (size <= pool_max [i]) {
-                       dma_pool_free (hcd->pool [i], addr, dma);
+                       dma_pool_free(hcd->pool [i], addr, dma);
                        return;
                }
        }
-       dma_free_coherent (hcd->self.controller, size, addr, dma);
+       dma_free_coherent(hcd->self.controller, size, addr, dma);
 }
index ea398e5..a47c30b 100644 (file)
@@ -104,7 +104,7 @@ static const char *format_config =
   
 static const char *format_iface =
 /* I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
-  "I:  If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
+  "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
 
 static const char *format_endpt =
 /* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
@@ -164,10 +164,10 @@ static const char *class_decode(const int class)
        for (ix = 0; clas_info[ix].class != -1; ix++)
                if (clas_info[ix].class == class)
                        break;
-       return (clas_info[ix].class_name);
+       return clas_info[ix].class_name;
 }
 
-static char *usb_dump_endpoint_descriptor (
+static char *usb_dump_endpoint_descriptor(
        int speed,
        char *start,
        char *end,
@@ -212,9 +212,9 @@ static char *usb_dump_endpoint_descriptor (
                break;
        case USB_ENDPOINT_XFER_INT:
                type = "Int.";
-               if (speed == USB_SPEED_HIGH) {
+               if (speed == USB_SPEED_HIGH)
                        interval = 1 << (desc->bInterval - 1);
-               else
+               else
                        interval = desc->bInterval;
                break;
        default:        /* "can't happen" */
@@ -242,15 +242,19 @@ static char *usb_dump_interface_descriptor(char *start, char *end,
 {
        const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
        const char *driver_name = "";
+       int active = 0;
 
        if (start > end)
                return start;
        down_read(&usb_bus_type.subsys.rwsem);
-       if (iface)
+       if (iface) {
                driver_name = (iface->dev.driver
                                ? iface->dev.driver->name
                                : "(none)");
+               active = (desc == &iface->cur_altsetting->desc);
+       }
        start += sprintf(start, format_iface,
+                        active ? '*' : ' ',    /* mark active altsetting */
                         desc->bInterfaceNumber,
                         desc->bAlternateSetting,
                         desc->bNumEndpoints,
@@ -343,7 +347,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
 
        if (start > end)
                return start;
-       start += sprintf (start, format_device1,
+       start += sprintf(start, format_device1,
                          bcdUSB >> 8, bcdUSB & 0xff,
                          desc->bDeviceClass,
                          class_decode (desc->bDeviceClass),
@@ -363,7 +367,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
 /*
  * Dump the different strings that this device holds.
  */
-static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
+static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev)
 {
        if (start > end)
                return start;
@@ -395,7 +399,7 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
        if (start > end)
                return start;
        
-       start = usb_dump_device_strings (start, end, dev);
+       start = usb_dump_device_strings(start, end, dev);
 
        for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
                if (start > end)
index 4b3a6ab..2087766 100644 (file)
@@ -522,19 +522,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
 
 static struct usb_device *usbdev_lookup_minor(int minor)
 {
-       struct class_device *class_dev;
-       struct usb_device *dev = NULL;
+       struct device *device;
+       struct usb_device *udev = NULL;
 
        down(&usb_device_class->sem);
-       list_for_each_entry(class_dev, &usb_device_class->children, node) {
-               if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
-                       dev = class_dev->class_data;
+       list_for_each_entry(device, &usb_device_class->devices, node) {
+               if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+                       udev = device->platform_data;
                        break;
                }
        }
        up(&usb_device_class->sem);
 
-       return dev;
+       return udev;
 };
 
 /*
@@ -570,6 +570,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
        ps->dev = dev;
        ps->file = file;
        spin_lock_init(&ps->lock);
+       INIT_LIST_HEAD(&ps->list);
        INIT_LIST_HEAD(&ps->async_pending);
        INIT_LIST_HEAD(&ps->async_completed);
        init_waitqueue_head(&ps->wait);
@@ -1596,19 +1597,19 @@ static int usbdev_add(struct usb_device *dev)
 {
        int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
 
-       dev->class_dev = class_device_create(usb_device_class, NULL,
-                               MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
+       dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
+                               MKDEV(USB_DEVICE_MAJOR, minor),
                                "usbdev%d.%d", dev->bus->busnum, dev->devnum);
-       if (IS_ERR(dev->class_dev))
-               return PTR_ERR(dev->class_dev);
+       if (IS_ERR(dev->usbfs_dev))
+               return PTR_ERR(dev->usbfs_dev);
 
-       dev->class_dev->class_data = dev;
+       dev->usbfs_dev->platform_data = dev;
        return 0;
 }
 
 static void usbdev_remove(struct usb_device *dev)
 {
-       class_device_unregister(dev->class_dev);
+       device_unregister(dev->usbfs_dev);
 }
 
 static int usbdev_notify(struct notifier_block *self, unsigned long action,
index d6eb5ce..600d1bc 100644 (file)
 #include "hcd.h"
 #include "usb.h"
 
-static int usb_match_one_id(struct usb_interface *interface,
-                           const struct usb_device_id *id);
-
-struct usb_dynid {
-       struct list_head node;
-       struct usb_device_id id;
-};
-
 #ifdef CONFIG_HOTPLUG
 
 /*
  * Adds a new dynamic USBdevice ID to this driver,
  * and cause the driver to probe for all devices again.
  */
-static ssize_t store_new_id(struct device_driver *driver,
-                           const char *buf, size_t count)
+ssize_t usb_store_new_id(struct usb_dynids *dynids,
+                        struct device_driver *driver,
+                        const char *buf, size_t count)
 {
-       struct usb_driver *usb_drv = to_usb_driver(driver);
        struct usb_dynid *dynid;
        u32 idVendor = 0;
        u32 idProduct = 0;
@@ -65,9 +57,9 @@ static ssize_t store_new_id(struct device_driver *driver,
        dynid->id.idProduct = idProduct;
        dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
 
-       spin_lock(&usb_drv->dynids.lock);
-       list_add_tail(&usb_drv->dynids.list, &dynid->node);
-       spin_unlock(&usb_drv->dynids.lock);
+       spin_lock(&dynids->lock);
+       list_add_tail(&dynids->list, &dynid->node);
+       spin_unlock(&dynids->lock);
 
        if (get_driver(driver)) {
                retval = driver_attach(driver);
@@ -78,6 +70,15 @@ static ssize_t store_new_id(struct device_driver *driver,
                return retval;
        return count;
 }
+EXPORT_SYMBOL_GPL(usb_store_new_id);
+
+static ssize_t store_new_id(struct device_driver *driver,
+                           const char *buf, size_t count)
+{
+       struct usb_driver *usb_drv = to_usb_driver(driver);
+
+       return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+}
 static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
 
 static int usb_create_newid_file(struct usb_driver *usb_drv)
@@ -365,8 +366,8 @@ void usb_driver_release_interface(struct usb_driver *driver,
 EXPORT_SYMBOL(usb_driver_release_interface);
 
 /* returns 0 if no match, 1 if match */
-static int usb_match_one_id(struct usb_interface *interface,
-                           const struct usb_device_id *id)
+int usb_match_one_id(struct usb_interface *interface,
+                    const struct usb_device_id *id)
 {
        struct usb_host_interface *intf;
        struct usb_device *dev;
@@ -432,6 +433,8 @@ static int usb_match_one_id(struct usb_interface *interface,
 
        return 1;
 }
+EXPORT_SYMBOL_GPL(usb_match_one_id);
+
 /**
  * usb_match_id - find first usb_device_id matching device or interface
  * @interface: the interface of interest
@@ -750,7 +753,8 @@ EXPORT_SYMBOL_GPL(usb_deregister_device_driver);
  * usb_register_dev() to enable that functionality.  This function no longer
  * takes care of that.
  */
-int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
+int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
+                       const char *mod_name)
 {
        int retval = 0;
 
@@ -763,6 +767,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
        new_driver->drvwrap.driver.probe = usb_probe_interface;
        new_driver->drvwrap.driver.remove = usb_unbind_interface;
        new_driver->drvwrap.driver.owner = owner;
+       new_driver->drvwrap.driver.mod_name = mod_name;
        spin_lock_init(&new_driver->dynids.lock);
        INIT_LIST_HEAD(&new_driver->dynids.list);
 
index f794f07..01c857a 100644 (file)
@@ -194,14 +194,13 @@ int usb_register_dev(struct usb_interface *intf,
                ++temp;
        else
                temp = name;
-       intf->class_dev = class_device_create(usb_class->class, NULL,
-                                             MKDEV(USB_MAJOR, minor),
-                                             &intf->dev, "%s", temp);
-       if (IS_ERR(intf->class_dev)) {
+       intf->usb_dev = device_create(usb_class->class, &intf->dev,
+                                     MKDEV(USB_MAJOR, minor), "%s", temp);
+       if (IS_ERR(intf->usb_dev)) {
                spin_lock (&minor_lock);
                usb_minors[intf->minor] = NULL;
                spin_unlock (&minor_lock);
-               retval = PTR_ERR(intf->class_dev);
+               retval = PTR_ERR(intf->usb_dev);
        }
 exit:
        return retval;
@@ -242,8 +241,8 @@ void usb_deregister_dev(struct usb_interface *intf,
        spin_unlock (&minor_lock);
 
        snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
-       class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
-       intf->class_dev = NULL;
+       device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
+       intf->usb_dev = NULL;
        intf->minor = -1;
        destroy_usb_class();
 }
index ebb20ff..b531a4f 100644 (file)
@@ -25,6 +25,20 @@ static inline const char *plural(int n)
        return (n == 1 ? "" : "s");
 }
 
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+       return desc->bInterfaceClass == USB_CLASS_COMM
+               && desc->bInterfaceSubClass == 2
+               && desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+       return desc->bInterfaceClass == USB_CLASS_MISC
+               && desc->bInterfaceSubClass == 1
+               && desc->bInterfaceProtocol == 1;
+}
+
 static int choose_configuration(struct usb_device *udev)
 {
        int i;
@@ -87,14 +101,12 @@ static int choose_configuration(struct usb_device *udev)
                        continue;
                }
 
-               /* If the first config's first interface is COMM/2/0xff
-                * (MSFT RNDIS), rule it out unless Linux has host-side
-                * RNDIS support. */
-               if (i == 0 && desc
-                               && desc->bInterfaceClass == USB_CLASS_COMM
-                               && desc->bInterfaceSubClass == 2
-                               && desc->bInterfaceProtocol == 0xff) {
-#ifndef CONFIG_USB_NET_RNDIS_HOST
+               /* When the first config's first interface is one of Microsoft's
+                * pet nonstandard Ethernet-over-USB protocols, ignore it unless
+                * this kernel has enabled the necessary host side driver.
+                */
+               if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) {
+#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
                        continue;
 #else
                        best = c;
index 10064af..b26c19e 100644 (file)
@@ -45,8 +45,6 @@
 #include "hub.h"
 
 
-// #define USB_BANDWIDTH_MESSAGES
-
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -891,136 +889,6 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
 }
 EXPORT_SYMBOL (usb_calc_bus_time);
 
-/*
- * usb_check_bandwidth():
- *
- * old_alloc is from host_controller->bandwidth_allocated in microseconds;
- * bustime is from calc_bus_time(), but converted to microseconds.
- *
- * returns <bustime in us> if successful,
- * or -ENOSPC if bandwidth request fails.
- *
- * FIXME:
- * This initial implementation does not use Endpoint.bInterval
- * in managing bandwidth allocation.
- * It probably needs to be expanded to use Endpoint.bInterval.
- * This can be done as a later enhancement (correction).
- *
- * This will also probably require some kind of
- * frame allocation tracking...meaning, for example,
- * that if multiple drivers request interrupts every 10 USB frames,
- * they don't all have to be allocated at
- * frame numbers N, N+10, N+20, etc.  Some of them could be at
- * N+11, N+21, N+31, etc., and others at
- * N+12, N+22, N+32, etc.
- *
- * Similarly for isochronous transfers...
- *
- * Individual HCDs can schedule more directly ... this logic
- * is not correct for high speed transfers.
- */
-int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
-{
-       unsigned int    pipe = urb->pipe;
-       long            bustime;
-       int             is_in = usb_pipein (pipe);
-       int             is_iso = usb_pipeisoc (pipe);
-       int             old_alloc = dev->bus->bandwidth_allocated;
-       int             new_alloc;
-
-
-       bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso,
-                       usb_maxpacket (dev, pipe, !is_in)));
-       if (is_iso)
-               bustime /= urb->number_of_packets;
-
-       new_alloc = old_alloc + (int) bustime;
-       if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) {
-#ifdef DEBUG
-               char    *mode = 
-#ifdef CONFIG_USB_BANDWIDTH
-                       "";
-#else
-                       "would have ";
-#endif
-               dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n",
-                       mode, old_alloc, bustime, new_alloc);
-#endif
-#ifdef CONFIG_USB_BANDWIDTH
-               bustime = -ENOSPC;      /* report error */
-#endif
-       }
-
-       return bustime;
-}
-EXPORT_SYMBOL (usb_check_bandwidth);
-
-
-/**
- * usb_claim_bandwidth - records bandwidth for a periodic transfer
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @bustime: bandwidth consumed, in (average) microseconds per frame
- * @isoc: true iff the request is isochronous
- *
- * Bus bandwidth reservations are recorded purely for diagnostic purposes.
- * HCDs are expected not to overcommit periodic bandwidth, and to record such
- * reservations whenever endpoints are added to the periodic schedule.
- *
- * FIXME averaging per-frame is suboptimal.  Better to sum over the HCD's
- * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable
- * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how
- * large its periodic schedule is.
- */
-void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
-{
-       dev->bus->bandwidth_allocated += bustime;
-       if (isoc)
-               dev->bus->bandwidth_isoc_reqs++;
-       else
-               dev->bus->bandwidth_int_reqs++;
-       urb->bandwidth = bustime;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-       dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n",
-               bustime,
-               isoc ? "ISOC" : "INTR",
-               dev->bus->bandwidth_allocated,
-               dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-}
-EXPORT_SYMBOL (usb_claim_bandwidth);
-
-
-/**
- * usb_release_bandwidth - reverses effect of usb_claim_bandwidth()
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @isoc: true iff the request is isochronous
- *
- * This records that previously allocated bandwidth has been released.
- * Bandwidth is released when endpoints are removed from the host controller's
- * periodic schedule.
- */
-void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
-{
-       dev->bus->bandwidth_allocated -= urb->bandwidth;
-       if (isoc)
-               dev->bus->bandwidth_isoc_reqs--;
-       else
-               dev->bus->bandwidth_int_reqs--;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-       dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n",
-               urb->bandwidth,
-               isoc ? "ISOC" : "INTR",
-               dev->bus->bandwidth_allocated,
-               dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-       urb->bandwidth = 0;
-}
-EXPORT_SYMBOL (usb_release_bandwidth);
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -1034,11 +902,6 @@ static void urb_unlink (struct urb *urb)
 {
        unsigned long           flags;
 
-       /* Release any periodic transfer bandwidth */
-       if (urb->bandwidth)
-               usb_release_bandwidth (urb->dev, urb,
-                       usb_pipeisoc (urb->pipe));
-
        /* clear all state linking urb to this dev (and hcd) */
 
        spin_lock_irqsave (&hcd_data_lock, flags);
index 8f8df0d..2a269ca 100644 (file)
@@ -308,10 +308,6 @@ extern void usb_destroy_configuration(struct usb_device *dev);
 #define NS_TO_US(ns)   ((ns + 500L) / 1000L)
                        /* convert & round nanoseconds to microseconds */
 
-extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
-               int bustime, int isoc);
-extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
-               int isoc);
 
 /*
  * Full/low speed bandwidth allocation constants/support.
@@ -324,8 +320,6 @@ extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
 #define FRAME_TIME_MAX_BITS_ALLOC      (90L * FRAME_TIME_BITS / 100L)
 #define FRAME_TIME_MAX_USECS_ALLOC     (90L * FRAME_TIME_USECS / 100L)
 
-extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
-
 /*
  * Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
  * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
index 1988224..590ec82 100644 (file)
@@ -87,9 +87,6 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
 
 static struct task_struct *khubd_task;
 
-/* multithreaded probe logic */
-static int multithread_probe = 0;
-
 /* cycle leds on hubs that aren't blinking for attention */
 static int blinkenlights = 0;
 module_param (blinkenlights, bool, S_IRUGO);
@@ -1256,9 +1253,28 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
 static int __usb_port_suspend(struct usb_device *, int port1);
 #endif
 
-static int __usb_new_device(void *void_data)
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured.  The device descriptor is available, but not descriptors
+ * for any device configuration.  The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not.  Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
 {
-       struct usb_device *udev = void_data;
        int err;
 
        /* Lock ourself into memory in order to keep a probe sequence
@@ -1375,44 +1391,6 @@ fail:
        goto exit;
 }
 
-/**
- * usb_new_device - perform initial device setup (usbcore-internal)
- * @udev: newly addressed device (in ADDRESS state)
- *
- * This is called with devices which have been enumerated, but not yet
- * configured.  The device descriptor is available, but not descriptors
- * for any device configuration.  The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * The return value for this function depends on if the
- * multithread_probe variable is set or not.  If it's set, it will
- * return a if the probe thread was successfully created or not.  If the
- * variable is not set, it will return if the device is configured
- * properly or not.  interfaces, in sysfs); else a negative errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
- */
-int usb_new_device(struct usb_device *udev)
-{
-       struct task_struct *probe_task;
-       int ret = 0;
-
-       if (multithread_probe) {
-               probe_task = kthread_run(__usb_new_device, udev,
-                                        "usb-probe-%s", udev->devnum);
-               if (IS_ERR(probe_task))
-                       ret = PTR_ERR(probe_task);
-       } else
-               ret = __usb_new_device(udev);
-
-       return ret;
-}
-
 static int hub_port_status(struct usb_hub *hub, int port1,
                               u16 *status, u16 *change)
 {
index 149aa8b..8aca357 100644 (file)
@@ -1545,11 +1545,7 @@ int usb_driver_set_configuration(struct usb_device *udev, int config)
        INIT_WORK(&req->work, driver_set_config_work);
 
        usb_get_dev(udev);
-       if (!schedule_work(&req->work)) {
-               usb_put_dev(udev);
-               kfree(req);
-               return -EINVAL;
-       }
+       schedule_work(&req->work);
        return 0;
 }
 EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
index 55d8f57..4eaa0ee 100644 (file)
 
 /* Active configuration fields */
 #define usb_actconfig_show(field, multiplier, format_string)           \
-static ssize_t  show_##field (struct device *dev,                      \
+static ssize_t  show_##field(struct device *dev,                       \
                struct device_attribute *attr, char *buf)               \
 {                                                                      \
        struct usb_device *udev;                                        \
        struct usb_host_config *actconfig;                              \
                                                                        \
-       udev = to_usb_device (dev);                                     \
+       udev = to_usb_device(dev);                                      \
        actconfig = udev->actconfig;                                    \
        if (actconfig)                                                  \
-               return sprintf (buf, format_string,                     \
+               return sprintf(buf, format_string,                      \
                                actconfig->desc.field * multiplier);    \
        else                                                            \
                return 0;                                               \
@@ -35,9 +35,9 @@ static ssize_t  show_##field (struct device *dev,                     \
 usb_actconfig_show(field, multiplier, format_string)                   \
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
-usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
-usb_actconfig_attr (bmAttributes, 1, "%2x\n")
-usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
+usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
+usb_actconfig_attr(bmAttributes, 1, "%2x\n")
+usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
 
 static ssize_t show_configuration_string(struct device *dev,
                struct device_attribute *attr, char *buf)
@@ -45,7 +45,7 @@ static ssize_t show_configuration_string(struct device *dev,
        struct usb_device *udev;
        struct usb_host_config *actconfig;
 
-       udev = to_usb_device (dev);
+       udev = to_usb_device(dev);
        actconfig = udev->actconfig;
        if ((!actconfig) || (!actconfig->string))
                return 0;
@@ -57,16 +57,16 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
 usb_actconfig_show(bConfigurationValue, 1, "%u\n");
 
 static ssize_t
-set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
+set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
-       struct usb_device       *udev = to_usb_device (dev);
+       struct usb_device       *udev = to_usb_device(dev);
        int                     config, value;
 
-       if (sscanf (buf, "%u", &config) != 1 || config > 255)
+       if (sscanf(buf, "%u", &config) != 1 || config > 255)
                return -EINVAL;
        usb_lock_device(udev);
-       value = usb_set_configuration (udev, config);
+       value = usb_set_configuration(udev, config);
        usb_unlock_device(udev);
        return (value < 0) ? value : count;
 }
@@ -81,7 +81,7 @@ static ssize_t  show_##name(struct device *dev,                               \
 {                                                                      \
        struct usb_device *udev;                                        \
                                                                        \
-       udev = to_usb_device (dev);                                     \
+       udev = to_usb_device(dev);                                      \
        return sprintf(buf, "%s\n", udev->name);                        \
 }                                                                      \
 static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
@@ -91,12 +91,12 @@ usb_string_attr(manufacturer);
 usb_string_attr(serial);
 
 static ssize_t
-show_speed (struct device *dev, struct device_attribute *attr, char *buf)
+show_speed(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct usb_device *udev;
        char *speed;
 
-       udev = to_usb_device (dev);
+       udev = to_usb_device(dev);
 
        switch (udev->speed) {
        case USB_SPEED_LOW:
@@ -112,22 +112,22 @@ show_speed (struct device *dev, struct device_attribute *attr, char *buf)
        default:
                speed = "unknown";
        }
-       return sprintf (buf, "%s\n", speed);
+       return sprintf(buf, "%s\n", speed);
 }
 static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
 
 static ssize_t
-show_devnum (struct device *dev, struct device_attribute *attr, char *buf)
+show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct usb_device *udev;
 
-       udev = to_usb_device (dev);
-       return sprintf (buf, "%d\n", udev->devnum);
+       udev = to_usb_device(dev);
+       return sprintf(buf, "%d\n", udev->devnum);
 }
 static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
 
 static ssize_t
-show_version (struct device *dev, struct device_attribute *attr, char *buf)
+show_version(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct usb_device *udev;
        u16 bcdUSB;
@@ -139,25 +139,25 @@ show_version (struct device *dev, struct device_attribute *attr, char *buf)
 static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
 
 static ssize_t
-show_maxchild (struct device *dev, struct device_attribute *attr, char *buf)
+show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct usb_device *udev;
 
-       udev = to_usb_device (dev);
-       return sprintf (buf, "%d\n", udev->maxchild);
+       udev = to_usb_device(dev);
+       return sprintf(buf, "%d\n", udev->maxchild);
 }
 static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
 
 /* Descriptor fields */
 #define usb_descriptor_attr_le16(field, format_string)                 \
 static ssize_t                                                         \
-show_##field (struct device *dev, struct device_attribute *attr,       \
+show_##field(struct device *dev, struct device_attribute *attr,        \
                char *buf)                                              \
 {                                                                      \
        struct usb_device *udev;                                        \
                                                                        \
-       udev = to_usb_device (dev);                                     \
-       return sprintf (buf, format_string,                             \
+       udev = to_usb_device(dev);                                      \
+       return sprintf(buf, format_string,                              \
                        le16_to_cpu(udev->descriptor.field));           \
 }                                                                      \
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
@@ -168,21 +168,21 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n")
 
 #define usb_descriptor_attr(field, format_string)                      \
 static ssize_t                                                         \
-show_##field (struct device *dev, struct device_attribute *attr,       \
+show_##field(struct device *dev, struct device_attribute *attr,        \
                char *buf)                                              \
 {                                                                      \
        struct usb_device *udev;                                        \
                                                                        \
-       udev = to_usb_device (dev);                                     \
-       return sprintf (buf, format_string, udev->descriptor.field);    \
+       udev = to_usb_device(dev);                                      \
+       return sprintf(buf, format_string, udev->descriptor.field);     \
 }                                                                      \
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
-usb_descriptor_attr (bDeviceClass, "%02x\n")
-usb_descriptor_attr (bDeviceSubClass, "%02x\n")
-usb_descriptor_attr (bDeviceProtocol, "%02x\n")
-usb_descriptor_attr (bNumConfigurations, "%d\n")
-usb_descriptor_attr (bMaxPacketSize0, "%d\n")
+usb_descriptor_attr(bDeviceClass, "%02x\n")
+usb_descriptor_attr(bDeviceSubClass, "%02x\n")
+usb_descriptor_attr(bDeviceProtocol, "%02x\n")
+usb_descriptor_attr(bNumConfigurations, "%d\n")
+usb_descriptor_attr(bMaxPacketSize0, "%d\n")
 
 static struct attribute *dev_attrs[] = {
        /* current configuration's attributes */
@@ -220,17 +220,17 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
                return retval;
 
        if (udev->manufacturer) {
-               retval = device_create_file (dev, &dev_attr_manufacturer);
+               retval = device_create_file(dev, &dev_attr_manufacturer);
                if (retval)
                        goto error;
        }
        if (udev->product) {
-               retval = device_create_file (dev, &dev_attr_product);
+               retval = device_create_file(dev, &dev_attr_product);
                if (retval)
                        goto error;
        }
        if (udev->serial) {
-               retval = device_create_file (dev, &dev_attr_serial);
+               retval = device_create_file(dev, &dev_attr_serial);
                if (retval)
                        goto error;
        }
@@ -246,7 +246,7 @@ error:
        return retval;
 }
 
-void usb_remove_sysfs_dev_files (struct usb_device *udev)
+void usb_remove_sysfs_dev_files(struct usb_device *udev)
 {
        struct device *dev = &udev->dev;
 
@@ -264,22 +264,22 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev)
 /* Interface fields */
 #define usb_intf_attr(field, format_string)                            \
 static ssize_t                                                         \
-show_##field (struct device *dev, struct device_attribute *attr,       \
+show_##field(struct device *dev, struct device_attribute *attr,        \
                char *buf)                                              \
 {                                                                      \
-       struct usb_interface *intf = to_usb_interface (dev);            \
+       struct usb_interface *intf = to_usb_interface(dev);             \
                                                                        \
-       return sprintf (buf, format_string,                             \
+       return sprintf(buf, format_string,                              \
                        intf->cur_altsetting->desc.field);              \
 }                                                                      \
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
-usb_intf_attr (bInterfaceNumber, "%02x\n")
-usb_intf_attr (bAlternateSetting, "%2d\n")
-usb_intf_attr (bNumEndpoints, "%02x\n")
-usb_intf_attr (bInterfaceClass, "%02x\n")
-usb_intf_attr (bInterfaceSubClass, "%02x\n")
-usb_intf_attr (bInterfaceProtocol, "%02x\n")
+usb_intf_attr(bInterfaceNumber, "%02x\n")
+usb_intf_attr(bAlternateSetting, "%2d\n")
+usb_intf_attr(bNumEndpoints, "%02x\n")
+usb_intf_attr(bInterfaceClass, "%02x\n")
+usb_intf_attr(bInterfaceSubClass, "%02x\n")
+usb_intf_attr(bInterfaceProtocol, "%02x\n")
 
 static ssize_t show_interface_string(struct device *dev,
                struct device_attribute *attr, char *buf)
@@ -288,8 +288,8 @@ static ssize_t show_interface_string(struct device *dev,
        struct usb_device *udev;
        int len;
 
-       intf = to_usb_interface (dev);
-       udev = interface_to_usbdev (intf);
+       intf = to_usb_interface(dev);
+       udev = interface_to_usbdev(intf);
        len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
        if (len < 0)
                return 0;
@@ -384,7 +384,7 @@ error:
        return retval;
 }
 
-void usb_remove_sysfs_intf_files (struct usb_interface *intf)
+void usb_remove_sysfs_intf_files(struct usb_interface *intf)
 {
        usb_remove_intf_ep_files(intf);
        sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
index 9801d08..94ea972 100644 (file)
@@ -235,16 +235,15 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 
        urb->status = -EINPROGRESS;
        urb->actual_length = 0;
-       urb->bandwidth = 0;
 
        /* Lots of sanity checks, so HCDs can rely on clean data
         * and don't need to duplicate tests
         */
        pipe = urb->pipe;
-       temp = usb_pipetype (pipe);
-       is_out = usb_pipeout (pipe);
+       temp = usb_pipetype(pipe);
+       is_out = usb_pipeout(pipe);
 
-       if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED)
+       if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
                return -ENODEV;
 
        /* FIXME there should be a sharable lock protecting us against
@@ -253,11 +252,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
         * checks get made.)
         */
 
-       max = usb_maxpacket (dev, pipe, is_out);
+       max = usb_maxpacket(dev, pipe, is_out);
        if (max <= 0) {
                dev_dbg(&dev->dev,
                        "bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
-                       usb_pipeendpoint (pipe), is_out ? "out" : "in",
+                       usb_pipeendpoint(pipe), is_out ? "out" : "in",
                        __FUNCTION__, max);
                return -EMSGSIZE;
        }
@@ -279,11 +278,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                if (urb->number_of_packets <= 0)                    
                        return -EINVAL;
                for (n = 0; n < urb->number_of_packets; n++) {
-                       len = urb->iso_frame_desc [n].length;
+                       len = urb->iso_frame_desc[n].length;
                        if (len < 0 || len > max) 
                                return -EMSGSIZE;
-                       urb->iso_frame_desc [n].status = -EXDEV;
-                       urb->iso_frame_desc [n].actual_length = 0;
+                       urb->iso_frame_desc[n].status = -EXDEV;
+                       urb->iso_frame_desc[n].actual_length = 0;
                }
        }
 
@@ -322,7 +321,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 
        /* fail if submitter gave bogus flags */
        if (urb->transfer_flags != orig_flags) {
-               err ("BOGUS urb flags, %x --> %x",
+               err("BOGUS urb flags, %x --> %x",
                        orig_flags, urb->transfer_flags);
                return -EINVAL;
        }
@@ -373,7 +372,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                urb->interval = temp;
        }
 
-       return usb_hcd_submit_urb (urb, mem_flags);
+       return usb_hcd_submit_urb(urb, mem_flags);
 }
 
 /*-------------------------------------------------------------------*/
index 02426d0..3db721c 100644 (file)
@@ -233,7 +233,7 @@ static void usb_autosuspend_work(struct work_struct *work)
  * @parent: hub to which device is connected; null to allocate a root hub
  * @bus: bus used to access the device
  * @port1: one-based index of port; ignored for root hubs
- * Context: !in_interrupt ()
+ * Context: !in_interrupt()
  *
  * Only hub drivers (including virtual root hub drivers for host
  * controllers) should ever call this.
@@ -277,22 +277,22 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
         * as stable:  bus->busnum changes easily from modprobe order,
         * cardbus or pci hotplugging, and so on.
         */
-       if (unlikely (!parent)) {
-               dev->devpath [0] = '0';
+       if (unlikely(!parent)) {
+               dev->devpath[0] = '0';
 
                dev->dev.parent = bus->controller;
-               sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum);
+               sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
        } else {
                /* match any labeling on the hubs; it's one-based */
-               if (parent->devpath [0] == '0')
-                       snprintf (dev->devpath, sizeof dev->devpath,
+               if (parent->devpath[0] == '0')
+                       snprintf(dev->devpath, sizeof dev->devpath,
                                "%d", port1);
                else
-                       snprintf (dev->devpath, sizeof dev->devpath,
+                       snprintf(dev->devpath, sizeof dev->devpath,
                                "%s.%d", parent->devpath, port1);
 
                dev->dev.parent = &parent->dev;
-               sprintf (&dev->dev.bus_id[0], "%d-%s",
+               sprintf(&dev->dev.bus_id[0], "%d-%s",
                        bus->busnum, dev->devpath);
 
                /* hub driver sets up TT records */
@@ -463,7 +463,7 @@ static struct usb_device *match_device(struct usb_device *dev,
        /* see if this device matches */
        if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
            (product_id == le16_to_cpu(dev->descriptor.idProduct))) {
-               dev_dbg (&dev->dev, "matched this device!\n");
+               dev_dbg(&dev->dev, "matched this device!\n");
                ret_dev = usb_get_dev(dev);
                goto exit;
        }
@@ -535,7 +535,7 @@ exit:
  */
 int usb_get_current_frame_number(struct usb_device *dev)
 {
-       return usb_hcd_get_frame_number (dev);
+       return usb_hcd_get_frame_number(dev);
 }
 
 /*-------------------------------------------------------------------*/
@@ -593,7 +593,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
  *
  * When the buffer is no longer used, free it with usb_buffer_free().
  */
-void *usb_buffer_alloc (
+void *usb_buffer_alloc(
        struct usb_device *dev,
        size_t size,
        gfp_t mem_flags,
@@ -602,7 +602,7 @@ void *usb_buffer_alloc (
 {
        if (!dev || !dev->bus)
                return NULL;
-       return hcd_buffer_alloc (dev->bus, size, mem_flags, dma);
+       return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
 }
 
 /**
@@ -616,7 +616,7 @@ void *usb_buffer_alloc (
  * been allocated using usb_buffer_alloc(), and the parameters must match
  * those provided in that allocation request. 
  */
-void usb_buffer_free (
+void usb_buffer_free(
        struct usb_device *dev,
        size_t size,
        void *addr,
@@ -627,7 +627,7 @@ void usb_buffer_free (
                return;
        if (!addr)
                return;
-       hcd_buffer_free (dev->bus, size, addr, dma);
+       hcd_buffer_free(dev->bus, size, addr, dma);
 }
 
 /**
@@ -647,7 +647,7 @@ void usb_buffer_free (
  * Reverse the effect of this call with usb_buffer_unmap().
  */
 #if 0
-struct urb *usb_buffer_map (struct urb *urb)
+struct urb *usb_buffer_map(struct urb *urb)
 {
        struct usb_bus          *bus;
        struct device           *controller;
@@ -659,14 +659,14 @@ struct urb *usb_buffer_map (struct urb *urb)
                return NULL;
 
        if (controller->dma_mask) {
-               urb->transfer_dma = dma_map_single (controller,
+               urb->transfer_dma = dma_map_single(controller,
                        urb->transfer_buffer, urb->transfer_buffer_length,
-                       usb_pipein (urb->pipe)
+                       usb_pipein(urb->pipe)
                                ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-               if (usb_pipecontrol (urb->pipe))
-                       urb->setup_dma = dma_map_single (controller,
+               if (usb_pipecontrol(urb->pipe))
+                       urb->setup_dma = dma_map_single(controller,
                                        urb->setup_packet,
-                                       sizeof (struct usb_ctrlrequest),
+                                       sizeof(struct usb_ctrlrequest),
                                        DMA_TO_DEVICE);
        // FIXME generic api broken like pci, can't report errors
        // if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
@@ -689,7 +689,7 @@ struct urb *usb_buffer_map (struct urb *urb)
  * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
  * @urb: urb whose transfer_buffer/setup_packet will be synchronized
  */
-void usb_buffer_dmasync (struct urb *urb)
+void usb_buffer_dmasync(struct urb *urb)
 {
        struct usb_bus          *bus;
        struct device           *controller;
@@ -702,14 +702,14 @@ void usb_buffer_dmasync (struct urb *urb)
                return;
 
        if (controller->dma_mask) {
-               dma_sync_single (controller,
+               dma_sync_single(controller,
                        urb->transfer_dma, urb->transfer_buffer_length,
-                       usb_pipein (urb->pipe)
+                       usb_pipein(urb->pipe)
                                ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-               if (usb_pipecontrol (urb->pipe))
-                       dma_sync_single (controller,
+               if (usb_pipecontrol(urb->pipe))
+                       dma_sync_single(controller,
                                        urb->setup_dma,
-                                       sizeof (struct usb_ctrlrequest),
+                                       sizeof(struct usb_ctrlrequest),
                                        DMA_TO_DEVICE);
        }
 }
@@ -722,7 +722,7 @@ void usb_buffer_dmasync (struct urb *urb)
  * Reverses the effect of usb_buffer_map().
  */
 #if 0
-void usb_buffer_unmap (struct urb *urb)
+void usb_buffer_unmap(struct urb *urb)
 {
        struct usb_bus          *bus;
        struct device           *controller;
@@ -735,14 +735,14 @@ void usb_buffer_unmap (struct urb *urb)
                return;
 
        if (controller->dma_mask) {
-               dma_unmap_single (controller,
+               dma_unmap_single(controller,
                        urb->transfer_dma, urb->transfer_buffer_length,
-                       usb_pipein (urb->pipe)
+                       usb_pipein(urb->pipe)
                                ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-               if (usb_pipecontrol (urb->pipe))
-                       dma_unmap_single (controller,
+               if (usb_pipecontrol(urb->pipe))
+                       dma_unmap_single(controller,
                                        urb->setup_dma,
-                                       sizeof (struct usb_ctrlrequest),
+                                       sizeof(struct usb_ctrlrequest),
                                        DMA_TO_DEVICE);
        }
        urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
@@ -783,15 +783,15 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
        struct device           *controller;
 
        if (!dev
-                       || usb_pipecontrol (pipe)
+                       || usb_pipecontrol(pipe)
                        || !(bus = dev->bus)
                        || !(controller = bus->controller)
                        || !controller->dma_mask)
                return -1;
 
        // FIXME generic api broken like pci, can't report errors
-       return dma_map_sg (controller, sg, nents,
-                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+       return dma_map_sg(controller, sg, nents,
+                       usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
@@ -823,8 +823,8 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
                        || !controller->dma_mask)
                return;
 
-       dma_sync_sg (controller, sg, n_hw_ents,
-                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+       dma_sync_sg(controller, sg, n_hw_ents,
+                       usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 #endif
 
@@ -849,8 +849,8 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
                        || !controller->dma_mask)
                return;
 
-       dma_unmap_sg (controller, sg, n_hw_ents,
-                       usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+       dma_unmap_sg(controller, sg, n_hw_ents,
+                       usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* format to disable USB on kernel command line is: nousb */
@@ -871,7 +871,7 @@ static int __init usb_init(void)
 {
        int retval;
        if (nousb) {
-               pr_info ("%s: USB support disabled\n", usbcore_name);
+               pr_info("%s: USB support disabled\n", usbcore_name);
                return 0;
        }
 
@@ -971,19 +971,19 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor);
 EXPORT_SYMBOL(usb_find_device);
 EXPORT_SYMBOL(usb_get_current_frame_number);
 
-EXPORT_SYMBOL (usb_buffer_alloc);
-EXPORT_SYMBOL (usb_buffer_free);
+EXPORT_SYMBOL(usb_buffer_alloc);
+EXPORT_SYMBOL(usb_buffer_free);
 
 #if 0
-EXPORT_SYMBOL (usb_buffer_map);
-EXPORT_SYMBOL (usb_buffer_dmasync);
-EXPORT_SYMBOL (usb_buffer_unmap);
+EXPORT_SYMBOL(usb_buffer_map);
+EXPORT_SYMBOL(usb_buffer_dmasync);
+EXPORT_SYMBOL(usb_buffer_unmap);
 #endif
 
-EXPORT_SYMBOL (usb_buffer_map_sg);
+EXPORT_SYMBOL(usb_buffer_map_sg);
 #if 0
-EXPORT_SYMBOL (usb_buffer_dmasync_sg);
+EXPORT_SYMBOL(usb_buffer_dmasync_sg);
 #endif
-EXPORT_SYMBOL (usb_buffer_unmap_sg);
+EXPORT_SYMBOL(usb_buffer_unmap_sg);
 
 MODULE_LICENSE("GPL");
index 812c733..f390501 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/clk.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/byteorder.h>
@@ -1807,16 +1807,13 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg)
                        || !wake
                        || at91_suspend_entering_slow_clock()) {
                pullup(udc, 0);
-               disable_irq_wake(udc->udp_irq);
+               wake = 0;
        } else
                enable_irq_wake(udc->udp_irq);
 
-       if (udc->board.vbus_pin > 0) {
-               if (wake)
-                       enable_irq_wake(udc->board.vbus_pin);
-               else
-                       disable_irq_wake(udc->board.vbus_pin);
-       }
+       udc->active_suspend = wake;
+       if (udc->board.vbus_pin > 0 && wake)
+               enable_irq_wake(udc->board.vbus_pin);
        return 0;
 }
 
@@ -1824,8 +1821,14 @@ static int at91udc_resume(struct platform_device *pdev)
 {
        struct at91_udc *udc = platform_get_drvdata(pdev);
 
+       if (udc->board.vbus_pin > 0 && udc->active_suspend)
+               disable_irq_wake(udc->board.vbus_pin);
+
        /* maybe reconnect to host; if so, clocks on */
-       pullup(udc, 1);
+       if (udc->active_suspend)
+               disable_irq_wake(udc->udp_irq);
+       else
+               pullup(udc, 1);
        return 0;
 }
 #else
index 677089b..7e34e2f 100644 (file)
@@ -136,6 +136,7 @@ struct at91_udc {
        unsigned                        wait_for_addr_ack:1;
        unsigned                        wait_for_config_ack:1;
        unsigned                        selfpowered:1;
+       unsigned                        active_suspend:1;
        u8                              addr;
        struct at91_udc_data            board;
        struct clk                      *iclk, *fclk;
index 83b4866..d18901b 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/string.h>
 #include <linux/device.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 
index 53d5845..f28af06 100644 (file)
@@ -27,7 +27,7 @@
 #include <linux/ctype.h>
 #include <linux/string.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
index d15bf22..22e3c94 100644 (file)
@@ -47,7 +47,7 @@
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb_gadget.h>
 
  *
  * There's some hardware that can't talk CDC.  We make that hardware
  * implement a "minimalist" vendor-agnostic CDC core:  same framing, but
- * link-level setup only requires activating the configuration.
- * Linux supports it, but other host operating systems may not.
- * (This is a subset of CDC Ethernet.)
+ * link-level setup only requires activating the configuration.  Only the
+ * endpoint descriptors, and product/vendor IDs, are relevant; no control
+ * operations are available.  Linux supports it, but other host operating
+ * systems may not.  (This is a subset of CDC Ethernet.)
+ *
+ * It turns out that if you add a few descriptors to that "CDC Subset",
+ * (Windows) host side drivers from MCCI can treat it as one submode of
+ * a proprietary scheme called "SAFE" ... without needing to know about
+ * specific product/vendor IDs.  So we do that, making it easier to use
+ * those MS-Windows drivers.  Those added descriptors make it resemble a
+ * CDC MDLM device, but they don't change device behavior at all.  (See
+ * MCCI Engineering report 950198 "SAFE Networking Functions".)
  *
  * A third option is also in use.  Rather than CDC Ethernet, or something
  * simpler, Microsoft pushes their own approach: RNDIS.  The published
@@ -254,6 +263,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define DEV_CONFIG_CDC
+#endif
+
 #ifdef CONFIG_USB_GADGET_AT91
 #define DEV_CONFIG_CDC
 #endif
@@ -266,6 +279,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define DEV_CONFIG_CDC
+#endif
+
 
 /* For CDC-incapable hardware, choose the simple cdc subset.
  * Anything that talks bulk (without notable bugs) can do this.
@@ -283,9 +300,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define        DEV_CONFIG_SUBSET
 #endif
 
-#ifdef CONFIG_USB_GADGET_S3C2410
-#define DEV_CONFIG_CDC
-#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -487,8 +501,17 @@ rndis_config = {
  * endpoint.  Both have a "data" interface and two bulk endpoints.
  * There are also differences in how control requests are handled.
  *
- * RNDIS shares a lot with CDC-Ethernet, since it's a variant of
- * the CDC-ACM (modem) spec.
+ * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the
+ * CDC-ACM (modem) spec.  Unfortunately MSFT's RNDIS driver is buggy; it
+ * may hang or oops.  Since bugfixes (or accurate specs, letting Linux
+ * work around those bugs) are unlikely to ever come from MSFT, you may
+ * wish to avoid using RNDIS.
+ *
+ * MCCI offers an alternative to RNDIS if you need to connect to Windows
+ * but have hardware that can't support CDC Ethernet.   We add descriptors
+ * to present the CDC Subset as a (nonconformant) CDC MDLM variant called
+ * "SAFE".  That borrows from both CDC Ethernet and CDC MDLM.  You can
+ * get those drivers from MCCI, or bundled with various products.
  */
 
 #ifdef DEV_CONFIG_CDC
@@ -522,8 +545,6 @@ rndis_control_intf = {
 };
 #endif
 
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-
 static const struct usb_cdc_header_desc header_desc = {
        .bLength =              sizeof header_desc,
        .bDescriptorType =      USB_DT_CS_INTERFACE,
@@ -532,6 +553,8 @@ static const struct usb_cdc_header_desc header_desc = {
        .bcdCDC =               __constant_cpu_to_le16 (0x0110),
 };
 
+#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+
 static const struct usb_cdc_union_desc union_desc = {
        .bLength =              sizeof union_desc,
        .bDescriptorType =      USB_DT_CS_INTERFACE,
@@ -564,7 +587,40 @@ static const struct usb_cdc_acm_descriptor acm_descriptor = {
 
 #endif
 
-#ifdef DEV_CONFIG_CDC
+#ifndef DEV_CONFIG_CDC
+
+/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various
+ * ways:  data endpoints live in the control interface, there's no data
+ * interface, and it's not used to talk to a cell phone radio.
+ */
+
+static const struct usb_cdc_mdlm_desc mdlm_desc = {
+       .bLength =              sizeof mdlm_desc,
+       .bDescriptorType =      USB_DT_CS_INTERFACE,
+       .bDescriptorSubType =   USB_CDC_MDLM_TYPE,
+
+       .bcdVersion =           __constant_cpu_to_le16(0x0100),
+       .bGUID = {
+               0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
+               0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
+       },
+};
+
+/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we
+ * can't really use its struct.  All we do here is say that we're using
+ * the submode of "SAFE" which directly matches the CDC Subset.
+ */
+static const u8 mdlm_detail_desc[] = {
+       6,
+       USB_DT_CS_INTERFACE,
+       USB_CDC_MDLM_DETAIL_TYPE,
+
+       0,      /* "SAFE" */
+       0,      /* network control capabilities (none) */
+       0,      /* network data capabilities ("raw" encapsulation) */
+};
+
+#endif
 
 static const struct usb_cdc_ether_desc ether_desc = {
        .bLength =              sizeof ether_desc,
@@ -579,7 +635,6 @@ static const struct usb_cdc_ether_desc ether_desc = {
        .bNumberPowerFilters =  0,
 };
 
-#endif
 
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
 
@@ -672,6 +727,9 @@ rndis_data_intf = {
 /*
  * "Simple" CDC-subset option is a simple vendor-neutral model that most
  * full speed controllers can handle:  one interface, two bulk endpoints.
+ *
+ * To assist host side drivers, we fancy it up a bit, and add descriptors
+ * so some host side drivers will understand it as a "SAFE" variant.
  */
 
 static const struct usb_interface_descriptor
@@ -682,8 +740,8 @@ subset_data_intf = {
        .bInterfaceNumber =     0,
        .bAlternateSetting =    0,
        .bNumEndpoints =        2,
-       .bInterfaceClass =      USB_CLASS_VENDOR_SPEC,
-       .bInterfaceSubClass =   0,
+       .bInterfaceClass =      USB_CLASS_COMM,
+       .bInterfaceSubClass =   USB_CDC_SUBCLASS_MDLM,
        .bInterfaceProtocol =   0,
        .iInterface =           STRING_DATA,
 };
@@ -731,10 +789,15 @@ static const struct usb_descriptor_header *fs_eth_function [11] = {
 static inline void __init fs_subset_descriptors(void)
 {
 #ifdef DEV_CONFIG_SUBSET
+       /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
        fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
-       fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
-       fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
-       fs_eth_function[4] = NULL;
+       fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+       fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+       fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+       fs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+       fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc;
+       fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc;
+       fs_eth_function[8] = NULL;
 #else
        fs_eth_function[1] = NULL;
 #endif
@@ -828,10 +891,15 @@ static const struct usb_descriptor_header *hs_eth_function [11] = {
 static inline void __init hs_subset_descriptors(void)
 {
 #ifdef DEV_CONFIG_SUBSET
+       /* behavior is "CDC Subset"; extra descriptors say "SAFE" */
        hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
-       hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
-       hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
-       hs_eth_function[4] = NULL;
+       hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+       hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+       hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+       hs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+       hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc;
+       hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc;
+       hs_eth_function[8] = NULL;
 #else
        hs_eth_function[1] = NULL;
 #endif
@@ -878,10 +946,8 @@ static char                                manufacturer [50];
 static char                            product_desc [40] = DRIVER_DESC;
 static char                            serial_number [20];
 
-#ifdef DEV_CONFIG_CDC
 /* address that the host will use ... usually assigned at random */
 static char                            ethaddr [2 * ETH_ALEN + 1];
-#endif
 
 /* static strings, in UTF-8 */
 static struct usb_string               strings [] = {
@@ -889,9 +955,9 @@ static struct usb_string            strings [] = {
        { STRING_PRODUCT,       product_desc, },
        { STRING_SERIALNUMBER,  serial_number, },
        { STRING_DATA,          "Ethernet Data", },
+       { STRING_ETHADDR,       ethaddr, },
 #ifdef DEV_CONFIG_CDC
        { STRING_CDC,           "CDC Ethernet", },
-       { STRING_ETHADDR,       ethaddr, },
        { STRING_CONTROL,       "CDC Communications Control", },
 #endif
 #ifdef DEV_CONFIG_SUBSET
@@ -986,10 +1052,10 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags)
        }
 #endif
 
-       dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
+       dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
        dev->in_ep->driver_data = dev;
 
-       dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
+       dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
        dev->out_ep->driver_data = dev;
 
        /* With CDC,  the host isn't allowed to use these two data
@@ -2278,10 +2344,10 @@ eth_bind (struct usb_gadget *gadget)
                        "RNDIS/%s", driver_desc);
 
        /* CDC subset ... recognized by Linux since 2.4.10, but Windows
-        * drivers aren't widely available.
+        * drivers aren't widely available.  (That may be improved by
+        * supporting one submode of the "SAFE" variant of MDLM.)
         */
        } else if (!cdc) {
-               device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
                device_desc.idVendor =
                        __constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
                device_desc.idProduct =
@@ -2352,6 +2418,10 @@ autoconf_fail:
        if (!cdc) {
                eth_config.bNumInterfaces = 1;
                eth_config.iConfiguration = STRING_SUBSET;
+
+               /* use functions to set these up, in case we're built to work
+                * with multiple controllers and must override CDC Ethernet.
+                */
                fs_subset_descriptors();
                hs_subset_descriptors();
        }
@@ -2415,22 +2485,20 @@ autoconf_fail:
 
        /* Module params for these addresses should come from ID proms.
         * The host side address is used with CDC and RNDIS, and commonly
-        * ends up in a persistent config database.
+        * ends up in a persistent config database.  It's not clear if
+        * host side code for the SAFE thing cares -- its original BLAN
+        * thing didn't, Sharp never assigned those addresses on Zaurii.
         */
        if (get_ether_addr(dev_addr, net->dev_addr))
                dev_warn(&gadget->dev,
                        "using random %s ethernet address\n", "self");
-       if (cdc || rndis) {
-               if (get_ether_addr(host_addr, dev->host_mac))
-                       dev_warn(&gadget->dev,
-                               "using random %s ethernet address\n", "host");
-#ifdef DEV_CONFIG_CDC
-               snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
-                       dev->host_mac [0], dev->host_mac [1],
-                       dev->host_mac [2], dev->host_mac [3],
-                       dev->host_mac [4], dev->host_mac [5]);
-#endif
-       }
+       if (get_ether_addr(host_addr, dev->host_mac))
+               dev_warn(&gadget->dev,
+                       "using random %s ethernet address\n", "host");
+       snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
+               dev->host_mac [0], dev->host_mac [1],
+               dev->host_mac [2], dev->host_mac [3],
+               dev->host_mac [4], dev->host_mac [5]);
 
        if (rndis) {
                status = rndis_init();
index 72f2ae9..f04a29a 100644 (file)
 #include <linux/freezer.h>
 #include <linux/utsname.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
@@ -1148,7 +1148,7 @@ static int ep0_queue(struct fsg_dev *fsg)
 
 static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
 {
-       struct fsg_dev          *fsg = (struct fsg_dev *) ep->driver_data;
+       struct fsg_dev          *fsg = ep->driver_data;
 
        if (req->actual > 0)
                dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
@@ -1170,8 +1170,8 @@ static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
 
 static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
 {
-       struct fsg_dev          *fsg = (struct fsg_dev *) ep->driver_data;
-       struct fsg_buffhd       *bh = (struct fsg_buffhd *) req->context;
+       struct fsg_dev          *fsg = ep->driver_data;
+       struct fsg_buffhd       *bh = req->context;
 
        if (req->status || req->actual != req->length)
                DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -1190,8 +1190,8 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
 
 static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
 {
-       struct fsg_dev          *fsg = (struct fsg_dev *) ep->driver_data;
-       struct fsg_buffhd       *bh = (struct fsg_buffhd *) req->context;
+       struct fsg_dev          *fsg = ep->driver_data;
+       struct fsg_buffhd       *bh = req->context;
 
        dump_msg(fsg, "bulk-out", req->buf, req->actual);
        if (req->status || req->actual != bh->bulk_out_intended_length)
@@ -1214,8 +1214,8 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
 #ifdef CONFIG_USB_FILE_STORAGE_TEST
 static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
 {
-       struct fsg_dev          *fsg = (struct fsg_dev *) ep->driver_data;
-       struct fsg_buffhd       *bh = (struct fsg_buffhd *) req->context;
+       struct fsg_dev          *fsg = ep->driver_data;
+       struct fsg_buffhd       *bh = req->context;
 
        if (req->status || req->actual != req->length)
                DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -2577,7 +2577,7 @@ static int send_status(struct fsg_dev *fsg)
        }
 
        if (transport_is_bbb()) {
-               struct bulk_cs_wrap     *csw = (struct bulk_cs_wrap *) bh->buf;
+               struct bulk_cs_wrap     *csw = bh->buf;
 
                /* Store and send the Bulk-only CSW */
                csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
@@ -2596,8 +2596,7 @@ static int send_status(struct fsg_dev *fsg)
                return 0;
 
        } else {                        // USB_PR_CBI
-               struct interrupt_data   *buf = (struct interrupt_data *)
-                                               bh->buf;
+               struct interrupt_data   *buf = bh->buf;
 
                /* Store and send the Interrupt data.  UFI sends the ASC
                 * and ASCQ bytes.  Everything else sends a Type (which
@@ -2982,7 +2981,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
 static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 {
        struct usb_request      *req = bh->outreq;
-       struct bulk_cb_wrap     *cbw = (struct bulk_cb_wrap *) req->buf;
+       struct bulk_cb_wrap     *cbw = req->buf;
 
        /* Was this a real packet? */
        if (req->status)
@@ -3428,7 +3427,7 @@ static void handle_exception(struct fsg_dev *fsg)
 
 static int fsg_main_thread(void *fsg_)
 {
-       struct fsg_dev          *fsg = (struct fsg_dev *) fsg_;
+       struct fsg_dev          *fsg = fsg_;
 
        /* Allow the thread to be killed by a signal, but set the signal mask
         * to block everything but INT, TERM, KILL, and USR1. */
@@ -3600,7 +3599,7 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
 static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
 {
        struct lun      *curlun = dev_to_lun(dev);
-       struct fsg_dev  *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+       struct fsg_dev  *fsg = dev_get_drvdata(dev);
        char            *p;
        ssize_t         rc;
 
@@ -3629,7 +3628,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
 {
        ssize_t         rc = count;
        struct lun      *curlun = dev_to_lun(dev);
-       struct fsg_dev  *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+       struct fsg_dev  *fsg = dev_get_drvdata(dev);
        int             i;
 
        if (sscanf(buf, "%d", &i) != 1)
@@ -3652,7 +3651,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
 static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
        struct lun      *curlun = dev_to_lun(dev);
-       struct fsg_dev  *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+       struct fsg_dev  *fsg = dev_get_drvdata(dev);
        int             rc = 0;
 
        if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) {
@@ -3700,7 +3699,7 @@ static void fsg_release(struct kref *ref)
 
 static void lun_release(struct device *dev)
 {
-       struct fsg_dev  *fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+       struct fsg_dev  *fsg = dev_get_drvdata(dev);
 
        kref_put(&fsg->ref, fsg_release);
 }
index aa80f09..2e3d662 100644 (file)
 #define        gadget_is_pxa27x(g)     0
 #endif
 
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define gadget_is_husb2dev(g)  !strcmp("husb2_udc", (g)->name)
+#else
+#define gadget_is_husb2dev(g)  0
+#endif
+
 #ifdef CONFIG_USB_GADGET_S3C2410
 #define gadget_is_s3c2410(g)    !strcmp("s3c2410_udc", (g)->name)
 #else
@@ -169,5 +175,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
                return 0x16;
        else if (gadget_is_mpc8272(gadget))
                return 0x17;
+       else if (gadget_is_husb2dev(gadget))
+               return 0x18;
        return -ENOENT;
 }
index f1a6796..d08a8d0 100644 (file)
@@ -35,7 +35,7 @@
 #include <sound/initval.h>
 #include <sound/rawmidi.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
index d0ef1d6..e873cf4 100644 (file)
@@ -39,7 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/byteorder.h>
index 3fb1044..34296e7 100644 (file)
@@ -20,7 +20,7 @@
  */
 
 
-// #define     DEBUG                   /* data to help fault diagnosis */
+// #define     DEBUG                   /* data to help fault diagnosis */
 // #define     VERBOSE         /* extra debug messages (success too) */
 
 #include <linux/init.h>
  *   may serve as a source of device events, used to handle all control
  *   requests other than basic enumeration.
  *
- * - Then either immediately, or after a SET_CONFIGURATION control request,
- *   ep_config() is called when each /dev/gadget/ep* file is configured
- *   (by writing endpoint descriptors).  Afterwards these files are used
- *   to write() IN data or to read() OUT data.  To halt the endpoint, a
- *   "wrong direction" request is issued (like reading an IN endpoint).
+ * - Then, after a SET_CONFIGURATION control request, ep_config() is
+ *   called when each /dev/gadget/ep* file is configured (by writing
+ *   endpoint descriptors).  Afterwards these files are used to write()
+ *   IN data or to read() OUT data.  To halt the endpoint, a "wrong
+ *   direction" request is issued (like reading an IN endpoint).
  *
  * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
  * not possible on all hardware.  For example, precise fault handling with
@@ -98,16 +98,16 @@ enum ep0_state {
         * must always write descriptors to initialize the device, then
         * the device becomes UNCONNECTED until enumeration.
         */
-       STATE_OPENED,
+       STATE_DEV_OPENED,
 
        /* From then on, ep0 fd is in either of two basic modes:
         * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
         * - SETUP: read/write will transfer control data and succeed;
         *   or if "wrong direction", performs protocol stall
         */
-       STATE_UNCONNECTED,
-       STATE_CONNECTED,
-       STATE_SETUP,
+       STATE_DEV_UNCONNECTED,
+       STATE_DEV_CONNECTED,
+       STATE_DEV_SETUP,
 
        /* UNBOUND means the driver closed ep0, so the device won't be
         * accessible again (DEV_DISABLED) until all fds are closed.
@@ -121,7 +121,7 @@ enum ep0_state {
 struct dev_data {
        spinlock_t                      lock;
        atomic_t                        count;
-       enum ep0_state                  state;
+       enum ep0_state                  state;          /* P: lock */
        struct usb_gadgetfs_event       event [N_EVENT];
        unsigned                        ev_next;
        struct fasync_struct            *fasync;
@@ -188,7 +188,6 @@ static struct dev_data *dev_new (void)
 enum ep_state {
        STATE_EP_DISABLED = 0,
        STATE_EP_READY,
-       STATE_EP_DEFER_ENABLE,
        STATE_EP_ENABLED,
        STATE_EP_UNBOUND,
 };
@@ -313,18 +312,10 @@ nonblock:
 
        if ((val = down_interruptible (&epdata->lock)) < 0)
                return val;
-newstate:
+
        switch (epdata->state) {
        case STATE_EP_ENABLED:
                break;
-       case STATE_EP_DEFER_ENABLE:
-               DBG (epdata->dev, "%s wait for host\n", epdata->name);
-               if ((val = wait_event_interruptible (epdata->wait, 
-                               epdata->state != STATE_EP_DEFER_ENABLE
-                               || epdata->dev->state == STATE_DEV_UNBOUND
-                               )) < 0)
-                       goto fail;
-               goto newstate;
        // case STATE_EP_DISABLED:              /* "can't happen" */
        // case STATE_EP_READY:                 /* "can't happen" */
        default:                                /* error! */
@@ -333,7 +324,6 @@ newstate:
                // FALLTHROUGH
        case STATE_EP_UNBOUND:                  /* clean disconnect */
                val = -ENODEV;
-fail:
                up (&epdata->lock);
        }
        return val;
@@ -565,29 +555,28 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
        ssize_t                 len, total;
        int                     i;
 
-       /* we "retry" to get the right mm context for this: */
-
-       /* copy stuff into user buffers */
-       total = priv->actual;
-       len = 0;
-       for (i=0; i < priv->nr_segs; i++) {
-               ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
-
-               if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
-                       if (len == 0)
-                               len = -EFAULT;
-                       break;
-               }
-
-               total -= this;
-               len += this;
-               if (total == 0)
-                       break;
-       }
-       kfree(priv->buf);
-       kfree(priv);
-       aio_put_req(iocb);
-       return len;
+       /* we "retry" to get the right mm context for this: */
+
+       /* copy stuff into user buffers */
+       total = priv->actual;
+       len = 0;
+       for (i=0; i < priv->nr_segs; i++) {
+               ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
+
+               if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
+                       if (len == 0)
+                               len = -EFAULT;
+                       break;
+               }
+
+               total -= this;
+               len += this;
+               if (total == 0)
+                       break;
+       }
+       kfree(priv->buf);
+       kfree(priv);
+       return len;
 }
 
 static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -600,18 +589,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
        spin_lock(&epdata->dev->lock);
        priv->req = NULL;
        priv->epdata = NULL;
-       if (priv->iv == NULL
-                       || unlikely(req->actual == 0)
-                       || unlikely(kiocbIsCancelled(iocb))) {
+
+       /* if this was a write or a read returning no data then we
+        * don't need to copy anything to userspace, so we can
+        * complete the aio request immediately.
+        */
+       if (priv->iv == NULL || unlikely(req->actual == 0)) {
                kfree(req->buf);
                kfree(priv);
                iocb->private = NULL;
                /* aio_complete() reports bytes-transferred _and_ faults */
-               if (unlikely(kiocbIsCancelled(iocb)))
-                       aio_put_req(iocb);
-               else
-                       aio_complete(iocb,
-                               req->actual ? req->actual : req->status,
+               aio_complete(iocb, req->actual ? req->actual : req->status,
                                req->status);
        } else {
                /* retry() won't report both; so we hide some faults */
@@ -636,7 +624,7 @@ ep_aio_rwtail(
        size_t          len,
        struct ep_data  *epdata,
        const struct iovec *iv,
-       unsigned long   nr_segs
+       unsigned long   nr_segs
 )
 {
        struct kiocb_priv       *priv;
@@ -852,9 +840,9 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                break;
 #endif
        default:
-               DBG (data->dev, "unconnected, %s init deferred\n",
+               DBG(data->dev, "unconnected, %s init abandoned\n",
                                data->name);
-               data->state = STATE_EP_DEFER_ENABLE;
+               value = -EINVAL;
        }
        if (value == 0) {
                fd->f_op = &ep_io_operations;
@@ -943,22 +931,24 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req)
 static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
 {
        struct dev_data         *dev = ep->driver_data;
+       unsigned long           flags;
        int                     free = 1;
 
        /* for control OUT, data must still get to userspace */
+       spin_lock_irqsave(&dev->lock, flags);
        if (!dev->setup_in) {
                dev->setup_out_error = (req->status != 0);
                if (!dev->setup_out_error)
                        free = 0;
                dev->setup_out_ready = 1;
                ep0_readable (dev);
-       } else if (dev->state == STATE_SETUP)
-               dev->state = STATE_CONNECTED;
+       }
 
        /* clean up as appropriate */
        if (free && req->buf != &dev->rbuf)
                clean_req (ep, req);
        req->complete = epio_complete;
+       spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
@@ -998,13 +988,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
        }
 
        /* control DATA stage */
-       if ((state = dev->state) == STATE_SETUP) {
+       if ((state = dev->state) == STATE_DEV_SETUP) {
 
                if (dev->setup_in) {            /* stall IN */
                        VDEBUG(dev, "ep0in stall\n");
                        (void) usb_ep_set_halt (dev->gadget->ep0);
                        retval = -EL2HLT;
-                       dev->state = STATE_CONNECTED;
+                       dev->state = STATE_DEV_CONNECTED;
 
                } else if (len == 0) {          /* ack SET_CONFIGURATION etc */
                        struct usb_ep           *ep = dev->gadget->ep0;
@@ -1012,7 +1002,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
 
                        if ((retval = setup_req (ep, req, 0)) == 0)
                                retval = usb_ep_queue (ep, req, GFP_ATOMIC);
-                       dev->state = STATE_CONNECTED;
+                       dev->state = STATE_DEV_CONNECTED;
 
                        /* assume that was SET_CONFIGURATION */
                        if (dev->current_config) {
@@ -1040,6 +1030,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
                        spin_lock_irq (&dev->lock);
                        if (retval)
                                goto done;
+
+                       if (dev->state != STATE_DEV_SETUP) {
+                               retval = -ECANCELED;
+                               goto done;
+                       }
+                       dev->state = STATE_DEV_CONNECTED;
+
                        if (dev->setup_out_error)
                                retval = -EIO;
                        else {
@@ -1066,39 +1063,36 @@ scan:
        /* return queued events right away */
        if (dev->ev_next != 0) {
                unsigned                i, n;
-               int                     tmp = dev->ev_next;
 
-               len = min (len, tmp * sizeof (struct usb_gadgetfs_event));
                n = len / sizeof (struct usb_gadgetfs_event);
+               if (dev->ev_next < n)
+                       n = dev->ev_next;
 
-               /* ep0 can't deliver events when STATE_SETUP */
+               /* ep0 i/o has special semantics during STATE_DEV_SETUP */
                for (i = 0; i < n; i++) {
                        if (dev->event [i].type == GADGETFS_SETUP) {
-                               len = i + 1;
-                               len *= sizeof (struct usb_gadgetfs_event);
-                               n = 0;
+                               dev->state = STATE_DEV_SETUP;
+                               n = i + 1;
                                break;
                        }
                }
                spin_unlock_irq (&dev->lock);
+               len = n * sizeof (struct usb_gadgetfs_event);
                if (copy_to_user (buf, &dev->event, len))
                        retval = -EFAULT;
                else
                        retval = len;
                if (len > 0) {
-                       len /= sizeof (struct usb_gadgetfs_event);
-
                        /* NOTE this doesn't guard against broken drivers;
                         * concurrent ep0 readers may lose events.
                         */
                        spin_lock_irq (&dev->lock);
-                       dev->ev_next -= len;
-                       if (dev->ev_next != 0)
-                               memmove (&dev->event, &dev->event [len],
+                       if (dev->ev_next > n) {
+                               memmove(&dev->event[0], &dev->event[n],
                                        sizeof (struct usb_gadgetfs_event)
-                                               * (tmp - len));
-                       if (n == 0)
-                               dev->state = STATE_SETUP;
+                                               * (dev->ev_next - n));
+                       }
+                       dev->ev_next -= n;
                        spin_unlock_irq (&dev->lock);
                }
                return retval;
@@ -1113,8 +1107,8 @@ scan:
                DBG (dev, "fail %s, state %d\n", __FUNCTION__, state);
                retval = -ESRCH;
                break;
-       case STATE_UNCONNECTED:
-       case STATE_CONNECTED:
+       case STATE_DEV_UNCONNECTED:
+       case STATE_DEV_CONNECTED:
                spin_unlock_irq (&dev->lock);
                DBG (dev, "%s wait\n", __FUNCTION__);
 
@@ -1141,7 +1135,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
        switch (type) {
        /* these events purge the queue */
        case GADGETFS_DISCONNECT:
-               if (dev->state == STATE_SETUP)
+               if (dev->state == STATE_DEV_SETUP)
                        dev->setup_abort = 1;
                // FALL THROUGH
        case GADGETFS_CONNECT:
@@ -1153,7 +1147,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
                for (i = 0; i != dev->ev_next; i++) {
                        if (dev->event [i].type != type)
                                continue;
-                       DBG (dev, "discard old event %d\n", type);
+                       DBG(dev, "discard old event[%d] %d\n", i, type);
                        dev->ev_next--;
                        if (i == dev->ev_next)
                                break;
@@ -1166,9 +1160,9 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
        default:
                BUG ();
        }
+       VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type);
        event = &dev->event [dev->ev_next++];
        BUG_ON (dev->ev_next > N_EVENT);
-       VDEBUG (dev, "ev %d, next %d\n", type, dev->ev_next);
        memset (event, 0, sizeof *event);
        event->type = type;
        return event;
@@ -1188,12 +1182,13 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                retval = -EIDRM;
 
        /* data and/or status stage for control request */
-       } else if (dev->state == STATE_SETUP) {
+       } else if (dev->state == STATE_DEV_SETUP) {
 
                /* IN DATA+STATUS caller makes len <= wLength */
                if (dev->setup_in) {
                        retval = setup_req (dev->gadget->ep0, dev->req, len);
                        if (retval == 0) {
+                               dev->state = STATE_DEV_CONNECTED;
                                spin_unlock_irq (&dev->lock);
                                if (copy_from_user (dev->req->buf, buf, len))
                                        retval = -EFAULT;
@@ -1219,7 +1214,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
                        VDEBUG(dev, "ep0out stall\n");
                        (void) usb_ep_set_halt (dev->gadget->ep0);
                        retval = -EL2HLT;
-                       dev->state = STATE_CONNECTED;
+                       dev->state = STATE_DEV_CONNECTED;
                } else {
                        DBG(dev, "bogus ep0out stall!\n");
                }
@@ -1261,7 +1256,9 @@ dev_release (struct inode *inode, struct file *fd)
        put_dev (dev);
 
        /* other endpoints were all decoupled from this device */
+       spin_lock_irq(&dev->lock);
        dev->state = STATE_DEV_DISABLED;
+       spin_unlock_irq(&dev->lock);
        return 0;
 }
 
@@ -1282,7 +1279,7 @@ ep0_poll (struct file *fd, poll_table *wait)
                goto out;
        }
 
-       if (dev->state == STATE_SETUP) {
+       if (dev->state == STATE_DEV_SETUP) {
                if (dev->setup_in || dev->setup_can_stall)
                        mask = POLLOUT;
        } else {
@@ -1392,52 +1389,29 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 
        spin_lock (&dev->lock);
        dev->setup_abort = 0;
-       if (dev->state == STATE_UNCONNECTED) {
-               struct usb_ep   *ep;
-               struct ep_data  *data;
-
-               dev->state = STATE_CONNECTED;
-               dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
-
+       if (dev->state == STATE_DEV_UNCONNECTED) {
 #ifdef CONFIG_USB_GADGET_DUALSPEED
                if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) {
+                       spin_unlock(&dev->lock);
                        ERROR (dev, "no high speed config??\n");
                        return -EINVAL;
                }
 #endif /* CONFIG_USB_GADGET_DUALSPEED */
 
+               dev->state = STATE_DEV_CONNECTED;
+               dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
+
                INFO (dev, "connected\n");
                event = next_event (dev, GADGETFS_CONNECT);
                event->u.speed = gadget->speed;
                ep0_readable (dev);
 
-               list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-                       data = ep->driver_data;
-                       /* ... down_trylock (&data->lock) ... */
-                       if (data->state != STATE_EP_DEFER_ENABLE)
-                               continue;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-                       if (gadget->speed == USB_SPEED_HIGH)
-                               value = usb_ep_enable (ep, &data->hs_desc);
-                       else
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-                               value = usb_ep_enable (ep, &data->desc);
-                       if (value) {
-                               ERROR (dev, "deferred %s enable --> %d\n",
-                                       data->name, value);
-                               continue;
-                       }
-                       data->state = STATE_EP_ENABLED;
-                       wake_up (&data->wait);
-                       DBG (dev, "woke up %s waiters\n", data->name);
-               }
-
        /* host may have given up waiting for response.  we can miss control
         * requests handled lower down (device/endpoint status and features);
         * then ep0_{read,write} will report the wrong status. controller
         * driver will have aborted pending i/o.
         */
-       } else if (dev->state == STATE_SETUP)
+       } else if (dev->state == STATE_DEV_SETUP)
                dev->setup_abort = 1;
 
        req->buf = dev->rbuf;
@@ -1583,7 +1557,7 @@ delegate:
        }
 
        /* proceed with data transfer and status phases? */
-       if (value >= 0 && dev->state != STATE_SETUP) {
+       if (value >= 0 && dev->state != STATE_DEV_SETUP) {
                req->length = value;
                req->zero = value < w_length;
                value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
@@ -1747,7 +1721,9 @@ gadgetfs_bind (struct usb_gadget *gadget)
                goto enomem;
 
        INFO (dev, "bound to %s driver\n", gadget->name);
-       dev->state = STATE_UNCONNECTED;
+       spin_lock_irq(&dev->lock);
+       dev->state = STATE_DEV_UNCONNECTED;
+       spin_unlock_irq(&dev->lock);
        get_dev (dev);
        return 0;
 
@@ -1762,11 +1738,9 @@ gadgetfs_disconnect (struct usb_gadget *gadget)
        struct dev_data         *dev = get_gadget_data (gadget);
 
        spin_lock (&dev->lock);
-       if (dev->state == STATE_UNCONNECTED) {
-               DBG (dev, "already unconnected\n");
+       if (dev->state == STATE_DEV_UNCONNECTED)
                goto exit;
-       }
-       dev->state = STATE_UNCONNECTED;
+       dev->state = STATE_DEV_UNCONNECTED;
 
        INFO (dev, "disconnected\n");
        next_event (dev, GADGETFS_DISCONNECT);
@@ -1783,9 +1757,9 @@ gadgetfs_suspend (struct usb_gadget *gadget)
        INFO (dev, "suspended from state %d\n", dev->state);
        spin_lock (&dev->lock);
        switch (dev->state) {
-       case STATE_SETUP:               // VERY odd... host died??
-       case STATE_CONNECTED:
-       case STATE_UNCONNECTED:
+       case STATE_DEV_SETUP:           // VERY odd... host died??
+       case STATE_DEV_CONNECTED:
+       case STATE_DEV_UNCONNECTED:
                next_event (dev, GADGETFS_SUSPEND);
                ep0_readable (dev);
                /* FALLTHROUGH */
@@ -1808,7 +1782,7 @@ static struct usb_gadget_driver gadgetfs_driver = {
        .disconnect     = gadgetfs_disconnect,
        .suspend        = gadgetfs_suspend,
 
-       .driver         = {
+       .driver = {
                .name           = (char *) shortname,
        },
 };
@@ -1829,7 +1803,7 @@ static struct usb_gadget_driver probe_driver = {
        .unbind         = gadgetfs_nop,
        .setup          = (void *)gadgetfs_nop,
        .disconnect     = gadgetfs_nop,
-       .driver         = {
+       .driver = {
                .name           = "nop",
        },
 };
@@ -1849,19 +1823,16 @@ static struct usb_gadget_driver probe_driver = {
  * . full/low speed config ... all wTotalLength bytes (with interface,
  *     class, altsetting, endpoint, and other descriptors)
  * . high speed config ... all descriptors, for high speed operation;
- *     this one's optional except for high-speed hardware
+ *     this one's optional except for high-speed hardware
  * . device descriptor
  *
- * Endpoints are not yet enabled. Drivers may want to immediately
- * initialize them, using the /dev/gadget/ep* files that are available
- * as soon as the kernel sees the configuration, or they can wait
- * until device configuration and interface altsetting changes create
+ * Endpoints are not yet enabled. Drivers must wait until device
+ * configuration and interface altsetting changes create
  * the need to configure (or unconfigure) them.
  *
  * After initialization, the device stays active for as long as that
- * $CHIP file is open.  Events may then be read from that descriptor,
- * such as configuration notifications.  More complex drivers will handle
- * some control requests in user space.
+ * $CHIP file is open.  Events must then be read from that descriptor,
+ * such as configuration notifications.
  */
 
 static int is_valid_config (struct usb_config_descriptor *config)
@@ -1884,9 +1855,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        u32                     tag;
        char                    *kbuf;
 
-       if (dev->state != STATE_OPENED)
-               return -EEXIST;
-
        if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
                return -EINVAL;
 
@@ -1978,13 +1946,15 @@ dev_open (struct inode *inode, struct file *fd)
        struct dev_data         *dev = inode->i_private;
        int                     value = -EBUSY;
 
+       spin_lock_irq(&dev->lock);
        if (dev->state == STATE_DEV_DISABLED) {
                dev->ev_next = 0;
-               dev->state = STATE_OPENED;
+               dev->state = STATE_DEV_OPENED;
                fd->private_data = dev;
                get_dev (dev);
                value = 0;
        }
+       spin_unlock_irq(&dev->lock);
        return value;
 }
 
index e3bb785..b3fe197 100644 (file)
@@ -49,7 +49,7 @@
 #include <asm/unaligned.h>
 #include <asm/hardware.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 /*
index 569eb8c..7617ff7 100644 (file)
@@ -63,7 +63,7 @@
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
 #include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/byteorder.h>
index cdcfd42..1401043 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
index b78de96..0d22536 100644 (file)
@@ -56,7 +56,7 @@
 #include <asm/arch/pxa-regs.h>
 #endif
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/arch/udc.h>
index f8a3ec6..6c742a9 100644 (file)
@@ -43,7 +43,7 @@
 #include <asm/unaligned.h>
 #include <asm/uaccess.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb_gadget.h>
 
index b173576..3459ea6 100644 (file)
@@ -14,7 +14,7 @@
 #include <linux/device.h>
 #include <linux/init.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/unaligned.h>
index 40710ea..ebe04e0 100644 (file)
@@ -84,7 +84,7 @@
 #include <asm/system.h>
 #include <asm/unaligned.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
index cc60759..6271187 100644 (file)
@@ -67,6 +67,11 @@ config USB_EHCI_TT_NEWSCHED
 
          If unsure, say N.
 
+config USB_EHCI_BIG_ENDIAN_MMIO
+       bool
+       depends on USB_EHCI_HCD
+       default n
+
 config USB_ISP116X_HCD
        tristate "ISP116X HCD support"
        depends on USB
@@ -101,21 +106,48 @@ config USB_OHCI_HCD_PPC_SOC
        bool "OHCI support for on-chip PPC USB controller"
        depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
        default y
-       select USB_OHCI_BIG_ENDIAN
+       select USB_OHCI_BIG_ENDIAN_DESC
+       select USB_OHCI_BIG_ENDIAN_MMIO
        ---help---
          Enables support for the USB controller on the MPC52xx or
          STB03xxx processor chip.  If unsure, say Y.
 
+config USB_OHCI_HCD_PPC_OF
+       bool "OHCI support for PPC USB controller on OF platform bus"
+       depends on USB_OHCI_HCD && PPC_OF
+       default y
+       ---help---
+         Enables support for the USB controller PowerPC present on the
+         OpenFirmware platform bus.
+
+config USB_OHCI_HCD_PPC_OF_BE
+       bool "Support big endian HC"
+       depends on USB_OHCI_HCD_PPC_OF
+       default y
+       select USB_OHCI_BIG_ENDIAN_DESC
+       select USB_OHCI_BIG_ENDIAN_MMIO
+
+config USB_OHCI_HCD_PPC_OF_LE
+       bool "Support little endian HC"
+       depends on USB_OHCI_HCD_PPC_OF
+       default n
+       select USB_OHCI_LITTLE_ENDIAN
+
 config USB_OHCI_HCD_PCI
        bool "OHCI support for PCI-bus USB controllers"
-       depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
+       depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
        default y
        select USB_OHCI_LITTLE_ENDIAN
        ---help---
          Enables support for PCI-bus plug-in USB controller cards.
          If unsure, say Y.
 
-config USB_OHCI_BIG_ENDIAN
+config USB_OHCI_BIG_ENDIAN_DESC
+       bool
+       depends on USB_OHCI_HCD
+       default n
+
+config USB_OHCI_BIG_ENDIAN_MMIO
        bool
        depends on USB_OHCI_HCD
        default n
index 56349d2..246afea 100644 (file)
@@ -43,7 +43,7 @@
  */
 static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
 {
-       u32     params = readl (&ehci->caps->hcs_params);
+       u32     params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
        ehci_dbg (ehci,
                "%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
@@ -87,7 +87,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
  * */
 static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
 {
-       u32     params = readl (&ehci->caps->hcc_params);
+       u32     params = ehci_readl(ehci, &ehci->caps->hcc_params);
 
        if (HCC_ISOC_CACHE (params)) {
                ehci_dbg (ehci,
@@ -653,7 +653,7 @@ show_registers (struct class_device *class_dev, char *buf)
        }
 
        /* Capability Registers */
-       i = HC_VERSION(readl (&ehci->caps->hc_capbase));
+       i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
        temp = scnprintf (next, size,
                "bus %s, device %s (driver " DRIVER_VERSION ")\n"
                "%s\n"
@@ -673,7 +673,7 @@ show_registers (struct class_device *class_dev, char *buf)
                unsigned        count = 256/4;
 
                pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
-               offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+               offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params));
                while (offset && count--) {
                        pci_read_config_dword (pdev, offset, &cap);
                        switch (cap & 0xff) {
@@ -704,50 +704,50 @@ show_registers (struct class_device *class_dev, char *buf)
 #endif
 
        // FIXME interpret both types of params
-       i = readl (&ehci->caps->hcs_params);
+       i = ehci_readl(ehci, &ehci->caps->hcs_params);
        temp = scnprintf (next, size, "structural params 0x%08x\n", i);
        size -= temp;
        next += temp;
 
-       i = readl (&ehci->caps->hcc_params);
+       i = ehci_readl(ehci, &ehci->caps->hcc_params);
        temp = scnprintf (next, size, "capability params 0x%08x\n", i);
        size -= temp;
        next += temp;
 
        /* Operational Registers */
        temp = dbg_status_buf (scratch, sizeof scratch, label,
-                       readl (&ehci->regs->status));
+                       ehci_readl(ehci, &ehci->regs->status));
        temp = scnprintf (next, size, fmt, temp, scratch);
        size -= temp;
        next += temp;
 
        temp = dbg_command_buf (scratch, sizeof scratch, label,
-                       readl (&ehci->regs->command));
+                       ehci_readl(ehci, &ehci->regs->command));
        temp = scnprintf (next, size, fmt, temp, scratch);
        size -= temp;
        next += temp;
 
        temp = dbg_intr_buf (scratch, sizeof scratch, label,
-                       readl (&ehci->regs->intr_enable));
+                       ehci_readl(ehci, &ehci->regs->intr_enable));
        temp = scnprintf (next, size, fmt, temp, scratch);
        size -= temp;
        next += temp;
 
        temp = scnprintf (next, size, "uframe %04x\n",
-                       readl (&ehci->regs->frame_index));
+                       ehci_readl(ehci, &ehci->regs->frame_index));
        size -= temp;
        next += temp;
 
        for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
                temp = dbg_port_buf (scratch, sizeof scratch, label, i,
-                               readl (&ehci->regs->port_status [i - 1]));
+                               ehci_readl(ehci, &ehci->regs->port_status [i - 1]));
                temp = scnprintf (next, size, fmt, temp, scratch);
                size -= temp;
                next += temp;
                if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
                        temp = scnprintf (next, size,
                                        "    debug control %08x\n",
-                                       readl (&ehci->debug->control));
+                                       ehci_readl(ehci, &ehci->debug->control));
                        size -= temp;
                        next += temp;
                }
index 1a915e9..a524805 100644 (file)
@@ -177,7 +177,7 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
        case FSL_USB2_PHY_NONE:
                break;
        }
-       writel(portsc, &ehci->regs->port_status[port_offset]);
+       ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
 }
 
 static void mpc83xx_usb_setup(struct usb_hcd *hcd)
@@ -214,7 +214,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
        }
 
        /* put controller in host mode. */
-       writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
+       ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
        out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
        out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
        out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
@@ -238,12 +238,12 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
        /* EHCI registers start at offset 0x100 */
        ehci->caps = hcd->regs + 0x100;
        ehci->regs = hcd->regs + 0x100 +
-           HC_LENGTH(readl(&ehci->caps->hc_capbase));
+           HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
 
        /* cache this readonly data; minimize chip reads */
-       ehci->hcs_params = readl(&ehci->caps->hcs_params);
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
        retval = ehci_halt(ehci);
        if (retval)
index 025d333..185721d 100644 (file)
@@ -157,12 +157,13 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
  * before driver shutdown. But it also seems to be caused by bugs in cardbus
  * bridge shutdown:  shutting down the bridge before the devices using it.
  */
-static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
+static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
+                     u32 mask, u32 done, int usec)
 {
        u32     result;
 
        do {
-               result = readl (ptr);
+               result = ehci_readl(ehci, ptr);
                if (result == ~(u32)0)          /* card removed */
                        return -ENODEV;
                result &= mask;
@@ -177,18 +178,19 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
 /* force HC to halt state from unknown (EHCI spec section 2.3) */
 static int ehci_halt (struct ehci_hcd *ehci)
 {
-       u32     temp = readl (&ehci->regs->status);
+       u32     temp = ehci_readl(ehci, &ehci->regs->status);
 
        /* disable any irqs left enabled by previous code */
-       writel (0, &ehci->regs->intr_enable);
+       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 
        if ((temp & STS_HALT) != 0)
                return 0;
 
-       temp = readl (&ehci->regs->command);
+       temp = ehci_readl(ehci, &ehci->regs->command);
        temp &= ~CMD_RUN;
-       writel (temp, &ehci->regs->command);
-       return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
+       ehci_writel(ehci, temp, &ehci->regs->command);
+       return handshake (ehci, &ehci->regs->status,
+                         STS_HALT, STS_HALT, 16 * 125);
 }
 
 /* put TDI/ARC silicon into EHCI mode */
@@ -198,23 +200,24 @@ static void tdi_reset (struct ehci_hcd *ehci)
        u32             tmp;
 
        reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
-       tmp = readl (reg_ptr);
+       tmp = ehci_readl(ehci, reg_ptr);
        tmp |= 0x3;
-       writel (tmp, reg_ptr);
+       ehci_writel(ehci, tmp, reg_ptr);
 }
 
 /* reset a non-running (STS_HALT == 1) controller */
 static int ehci_reset (struct ehci_hcd *ehci)
 {
        int     retval;
-       u32     command = readl (&ehci->regs->command);
+       u32     command = ehci_readl(ehci, &ehci->regs->command);
 
        command |= CMD_RESET;
        dbg_cmd (ehci, "reset", command);
-       writel (command, &ehci->regs->command);
+       ehci_writel(ehci, command, &ehci->regs->command);
        ehci_to_hcd(ehci)->state = HC_STATE_HALT;
        ehci->next_statechange = jiffies;
-       retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+       retval = handshake (ehci, &ehci->regs->command,
+                           CMD_RESET, 0, 250 * 1000);
 
        if (retval)
                return retval;
@@ -236,21 +239,21 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
 #endif
 
        /* wait for any schedule enables/disables to take effect */
-       temp = readl (&ehci->regs->command) << 10;
+       temp = ehci_readl(ehci, &ehci->regs->command) << 10;
        temp &= STS_ASS | STS_PSS;
-       if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+       if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
                                temp, 16 * 125) != 0) {
                ehci_to_hcd(ehci)->state = HC_STATE_HALT;
                return;
        }
 
        /* then disable anything that's still active */
-       temp = readl (&ehci->regs->command);
+       temp = ehci_readl(ehci, &ehci->regs->command);
        temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
-       writel (temp, &ehci->regs->command);
+       ehci_writel(ehci, temp, &ehci->regs->command);
 
        /* hardware can take 16 microframes to turn off ... */
-       if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+       if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
                                0, 16 * 125) != 0) {
                ehci_to_hcd(ehci)->state = HC_STATE_HALT;
                return;
@@ -277,11 +280,11 @@ static void ehci_watchdog (unsigned long param)
 
        /* lost IAA irqs wedge things badly; seen with a vt8235 */
        if (ehci->reclaim) {
-               u32             status = readl (&ehci->regs->status);
+               u32             status = ehci_readl(ehci, &ehci->regs->status);
                if (status & STS_IAA) {
                        ehci_vdbg (ehci, "lost IAA\n");
                        COUNT (ehci->stats.lost_iaa);
-                       writel (STS_IAA, &ehci->regs->status);
+                       ehci_writel(ehci, STS_IAA, &ehci->regs->status);
                        ehci->reclaim_ready = 1;
                }
        }
@@ -309,7 +312,7 @@ ehci_shutdown (struct usb_hcd *hcd)
        (void) ehci_halt (ehci);
 
        /* make BIOS/etc use companion controller during reboot */
-       writel (0, &ehci->regs->configured_flag);
+       ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 }
 
 static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@@ -379,12 +382,13 @@ static void ehci_stop (struct usb_hcd *hcd)
                ehci_quiesce (ehci);
 
        ehci_reset (ehci);
-       writel (0, &ehci->regs->intr_enable);
+       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
        spin_unlock_irq(&ehci->lock);
 
        /* let companion controllers work when we aren't */
-       writel (0, &ehci->regs->configured_flag);
+       ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 
+       remove_companion_file(ehci);
        remove_debug_files (ehci);
 
        /* root hub is shut down separately (first, when possible) */
@@ -402,7 +406,8 @@ static void ehci_stop (struct usb_hcd *hcd)
                ehci->stats.complete, ehci->stats.unlink);
 #endif
 
-       dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+       dbg_status (ehci, "ehci_stop completed",
+                   ehci_readl(ehci, &ehci->regs->status));
 }
 
 /* one-time init, only for memory state */
@@ -428,7 +433,7 @@ static int ehci_init(struct usb_hcd *hcd)
                return retval;
 
        /* controllers may cache some of the periodic schedule ... */
-       hcc_params = readl(&ehci->caps->hcc_params);
+       hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
        if (HCC_ISOC_CACHE(hcc_params))         // full frame cache
                ehci->i_thresh = 8;
        else                                    // N microframes cached
@@ -496,13 +501,16 @@ static int ehci_run (struct usb_hcd *hcd)
        u32                     temp;
        u32                     hcc_params;
 
+       hcd->uses_new_polling = 1;
+       hcd->poll_rh = 0;
+
        /* EHCI spec section 4.1 */
        if ((retval = ehci_reset(ehci)) != 0) {
                ehci_mem_cleanup(ehci);
                return retval;
        }
-       writel(ehci->periodic_dma, &ehci->regs->frame_list);
-       writel((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+       ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+       ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
 
        /*
         * hcc_params controls whether ehci->regs->segment must (!!!)
@@ -516,9 +524,9 @@ static int ehci_run (struct usb_hcd *hcd)
         * Scsi_Host.highmem_io, and so forth.  It's readonly to all
         * host side drivers though.
         */
-       hcc_params = readl(&ehci->caps->hcc_params);
+       hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
        if (HCC_64BIT_ADDR(hcc_params)) {
-               writel(0, &ehci->regs->segment);
+               ehci_writel(ehci, 0, &ehci->regs->segment);
 #if 0
 // this is deeply broken on almost all architectures
                if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK))
@@ -531,7 +539,7 @@ static int ehci_run (struct usb_hcd *hcd)
        // root hub will detect new devices (why?); NEC doesn't
        ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
        ehci->command |= CMD_RUN;
-       writel (ehci->command, &ehci->regs->command);
+       ehci_writel(ehci, ehci->command, &ehci->regs->command);
        dbg_cmd (ehci, "init", ehci->command);
 
        /*
@@ -541,23 +549,25 @@ static int ehci_run (struct usb_hcd *hcd)
         * and there's no companion controller unless maybe for USB OTG.)
         */
        hcd->state = HC_STATE_RUNNING;
-       writel (FLAG_CF, &ehci->regs->configured_flag);
-       readl (&ehci->regs->command);   /* unblock posted writes */
+       ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+       ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
 
-       temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
+       temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
        ehci_info (ehci,
                "USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
                ((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
                temp >> 8, temp & 0xff, DRIVER_VERSION,
                ignore_oc ? ", overcurrent ignored" : "");
 
-       writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
+       ehci_writel(ehci, INTR_MASK,
+                   &ehci->regs->intr_enable); /* Turn On Interrupts */
 
        /* GRR this is run-once init(), being done every time the HC starts.
         * So long as they're part of class devices, we can't do it init()
         * since the class device isn't created that early.
         */
        create_debug_files(ehci);
+       create_companion_file(ehci);
 
        return 0;
 }
@@ -567,12 +577,12 @@ static int ehci_run (struct usb_hcd *hcd)
 static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
-       u32                     status;
+       u32                     status, pcd_status = 0;
        int                     bh;
 
        spin_lock (&ehci->lock);
 
-       status = readl (&ehci->regs->status);
+       status = ehci_readl(ehci, &ehci->regs->status);
 
        /* e.g. cardbus physical eject */
        if (status == ~(u32) 0) {
@@ -587,8 +597,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
        }
 
        /* clear (just) interrupts */
-       writel (status, &ehci->regs->status);
-       readl (&ehci->regs->command);   /* unblock posted write */
+       ehci_writel(ehci, status, &ehci->regs->status);
+       ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
        bh = 0;
 
 #ifdef EHCI_VERBOSE_DEBUG
@@ -617,13 +627,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
        /* remote wakeup [4.3.1] */
        if (status & STS_PCD) {
                unsigned        i = HCS_N_PORTS (ehci->hcs_params);
+               pcd_status = status;
 
                /* resume root hub? */
-               if (!(readl(&ehci->regs->command) & CMD_RUN))
+               if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN))
                        usb_hcd_resume_root_hub(hcd);
 
                while (i--) {
-                       int pstatus = readl (&ehci->regs->port_status [i]);
+                       int pstatus = ehci_readl(ehci,
+                                                &ehci->regs->port_status [i]);
 
                        if (pstatus & PORT_OWNER)
                                continue;
@@ -643,14 +655,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
        /* PCI errors [4.15.2.4] */
        if (unlikely ((status & STS_FATAL) != 0)) {
                /* bogus "fatal" IRQs appear on some chips... why?  */
-               status = readl (&ehci->regs->status);
-               dbg_cmd (ehci, "fatal", readl (&ehci->regs->command));
+               status = ehci_readl(ehci, &ehci->regs->status);
+               dbg_cmd (ehci, "fatal", ehci_readl(ehci,
+                                                  &ehci->regs->command));
                dbg_status (ehci, "fatal", status);
                if (status & STS_HALT) {
                        ehci_err (ehci, "fatal error\n");
 dead:
                        ehci_reset (ehci);
-                       writel (0, &ehci->regs->configured_flag);
+                       ehci_writel(ehci, 0, &ehci->regs->configured_flag);
                        /* generic layer kills/unlinks all urbs, then
                         * uses ehci_stop to clean up the rest
                         */
@@ -661,6 +674,8 @@ dead:
        if (bh)
                ehci_work (ehci);
        spin_unlock (&ehci->lock);
+       if (pcd_status & STS_PCD)
+               usb_hcd_poll_rh_status(hcd);
        return IRQ_HANDLED;
 }
 
@@ -873,7 +888,8 @@ done:
 static int ehci_get_frame (struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
-       return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
+       return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
+               ehci->periodic_size;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -899,7 +915,13 @@ MODULE_LICENSE ("GPL");
 #define        PLATFORM_DRIVER         ehci_hcd_au1xxx_driver
 #endif
 
-#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
+#ifdef CONFIG_PPC_PS3
+#include "ehci-ps3.c"
+#define        PS3_SYSTEM_BUS_DRIVER   ps3_ehci_sb_driver
+#endif
+
+#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+    !defined(PS3_SYSTEM_BUS_DRIVER)
 #error "missing bus glue for ehci-hcd"
 #endif
 
@@ -924,6 +946,20 @@ static int __init ehci_hcd_init(void)
 #ifdef PLATFORM_DRIVER
                platform_driver_unregister(&PLATFORM_DRIVER);
 #endif
+               return retval;
+       }
+#endif
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+       if (retval < 0) {
+#ifdef PLATFORM_DRIVER
+               platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PCI_DRIVER
+               pci_unregister_driver(&PCI_DRIVER);
+#endif
+               return retval;
        }
 #endif
 
@@ -939,6 +975,9 @@ static void __exit ehci_hcd_cleanup(void)
 #ifdef PCI_DRIVER
        pci_unregister_driver(&PCI_DRIVER);
 #endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
 }
 module_exit(ehci_hcd_cleanup);
 
index bfe5f30..0d83c6d 100644 (file)
@@ -47,7 +47,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                ehci_quiesce (ehci);
                hcd->state = HC_STATE_QUIESCING;
        }
-       ehci->command = readl (&ehci->regs->command);
+       ehci->command = ehci_readl(ehci, &ehci->regs->command);
        if (ehci->reclaim)
                ehci->reclaim_ready = 1;
        ehci_work(ehci);
@@ -60,7 +60,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
        ehci->bus_suspended = 0;
        while (port--) {
                u32 __iomem     *reg = &ehci->regs->port_status [port];
-               u32             t1 = readl (reg) & ~PORT_RWC_BITS;
+               u32             t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
                u32             t2 = t1;
 
                /* keep track of which ports we suspend */
@@ -79,7 +79,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
                if (t1 != t2) {
                        ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
                                port + 1, t1, t2);
-                       writel (t2, reg);
+                       ehci_writel(ehci, t2, reg);
                }
        }
 
@@ -92,8 +92,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
        mask = INTR_MASK;
        if (!device_may_wakeup(&hcd->self.root_hub->dev))
                mask &= ~STS_PCD;
-       writel(mask, &ehci->regs->intr_enable);
-       readl(&ehci->regs->intr_enable);
+       ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+       ehci_readl(ehci, &ehci->regs->intr_enable);
 
        ehci->next_statechange = jiffies + msecs_to_jiffies(10);
        spin_unlock_irq (&ehci->lock);
@@ -118,26 +118,26 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
         * the last user of the controller, not reset/pm hardware keeping
         * state we gave to it.
         */
-       temp = readl(&ehci->regs->intr_enable);
+       temp = ehci_readl(ehci, &ehci->regs->intr_enable);
        ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
 
        /* at least some APM implementations will try to deliver
         * IRQs right away, so delay them until we're ready.
         */
-       writel(0, &ehci->regs->intr_enable);
+       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 
        /* re-init operational registers */
-       writel(0, &ehci->regs->segment);
-       writel(ehci->periodic_dma, &ehci->regs->frame_list);
-       writel((u32) ehci->async->qh_dma, &ehci->regs->async_next);
+       ehci_writel(ehci, 0, &ehci->regs->segment);
+       ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+       ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
 
        /* restore CMD_RUN, framelist size, and irq threshold */
-       writel (ehci->command, &ehci->regs->command);
+       ehci_writel(ehci, ehci->command, &ehci->regs->command);
 
        /* manually resume the ports we suspended during bus_suspend() */
        i = HCS_N_PORTS (ehci->hcs_params);
        while (i--) {
-               temp = readl (&ehci->regs->port_status [i]);
+               temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
                temp &= ~(PORT_RWC_BITS
                        | PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
                if (test_bit(i, &ehci->bus_suspended) &&
@@ -145,20 +145,20 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
                        ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
                        temp |= PORT_RESUME;
                }
-               writel (temp, &ehci->regs->port_status [i]);
+               ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
        }
        i = HCS_N_PORTS (ehci->hcs_params);
        mdelay (20);
        while (i--) {
-               temp = readl (&ehci->regs->port_status [i]);
+               temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
                if (test_bit(i, &ehci->bus_suspended) &&
                                (temp & PORT_SUSPEND)) {
                        temp &= ~(PORT_RWC_BITS | PORT_RESUME);
-                       writel (temp, &ehci->regs->port_status [i]);
+                       ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
                        ehci_vdbg (ehci, "resumed port %d\n", i + 1);
                }
        }
-       (void) readl (&ehci->regs->command);
+       (void) ehci_readl(ehci, &ehci->regs->command);
 
        /* maybe re-activate the schedule(s) */
        temp = 0;
@@ -168,14 +168,14 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
                temp |= CMD_PSE;
        if (temp) {
                ehci->command |= temp;
-               writel (ehci->command, &ehci->regs->command);
+               ehci_writel(ehci, ehci->command, &ehci->regs->command);
        }
 
        ehci->next_statechange = jiffies + msecs_to_jiffies(5);
        hcd->state = HC_STATE_RUNNING;
 
        /* Now we can safely re-enable irqs */
-       writel(INTR_MASK, &ehci->regs->intr_enable);
+       ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
 
        spin_unlock_irq (&ehci->lock);
        return 0;
@@ -188,11 +188,109 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 
 #endif /* CONFIG_PM */
 
+/*-------------------------------------------------------------------------*/
+
+/* Display the ports dedicated to the companion controller */
+static ssize_t show_companion(struct class_device *class_dev, char *buf)
+{
+       struct ehci_hcd         *ehci;
+       int                     nports, index, n;
+       int                     count = PAGE_SIZE;
+       char                    *ptr = buf;
+
+       ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+       nports = HCS_N_PORTS(ehci->hcs_params);
+
+       for (index = 0; index < nports; ++index) {
+               if (test_bit(index, &ehci->companion_ports)) {
+                       n = scnprintf(ptr, count, "%d\n", index + 1);
+                       ptr += n;
+                       count -= n;
+               }
+       }
+       return ptr - buf;
+}
+
+/*
+ * Dedicate or undedicate a port to the companion controller.
+ * Syntax is "[-]portnum", where a leading '-' sign means
+ * return control of the port to the EHCI controller.
+ */
+static ssize_t store_companion(struct class_device *class_dev,
+               const char *buf, size_t count)
+{
+       struct ehci_hcd         *ehci;
+       int                     portnum, new_owner, try;
+       u32 __iomem             *status_reg;
+       u32                     port_status;
+
+       ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+       new_owner = PORT_OWNER;         /* Owned by companion */
+       if (sscanf(buf, "%d", &portnum) != 1)
+               return -EINVAL;
+       if (portnum < 0) {
+               portnum = - portnum;
+               new_owner = 0;          /* Owned by EHCI */
+       }
+       if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
+               return -ENOENT;
+       status_reg = &ehci->regs->port_status[--portnum];
+       if (new_owner)
+               set_bit(portnum, &ehci->companion_ports);
+       else
+               clear_bit(portnum, &ehci->companion_ports);
+
+       /*
+        * The controller won't set the OWNER bit if the port is
+        * enabled, so this loop will sometimes require at least two
+        * iterations: one to disable the port and one to set OWNER.
+        */
+
+       for (try = 4; try > 0; --try) {
+               spin_lock_irq(&ehci->lock);
+               port_status = ehci_readl(ehci, status_reg);
+               if ((port_status & PORT_OWNER) == new_owner
+                               || (port_status & (PORT_OWNER | PORT_CONNECT))
+                                       == 0)
+                       try = 0;
+               else {
+                       port_status ^= PORT_OWNER;
+                       port_status &= ~(PORT_PE | PORT_RWC_BITS);
+                       ehci_writel(ehci, port_status, status_reg);
+               }
+               spin_unlock_irq(&ehci->lock);
+               if (try > 1)
+                       msleep(5);
+       }
+       return count;
+}
+static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
+
+static inline void create_companion_file(struct ehci_hcd *ehci)
+{
+       int     i;
+
+       /* with integrated TT there is no companion! */
+       if (!ehci_is_TDI(ehci))
+               i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev,
+                               &class_device_attr_companion);
+}
+
+static inline void remove_companion_file(struct ehci_hcd *ehci)
+{
+       /* with integrated TT there is no companion! */
+       if (!ehci_is_TDI(ehci))
+               class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev,
+                               &class_device_attr_companion);
+}
+
+
 /*-------------------------------------------------------------------------*/
 
 static int check_reset_complete (
        struct ehci_hcd *ehci,
        int             index,
+       u32 __iomem     *status_reg,
        int             port_status
 ) {
        if (!(port_status & PORT_CONNECT)) {
@@ -217,7 +315,7 @@ static int check_reset_complete (
                // what happens if HCS_N_CC(params) == 0 ?
                port_status |= PORT_OWNER;
                port_status &= ~PORT_RWC_BITS;
-               writel (port_status, &ehci->regs->port_status [index]);
+               ehci_writel(ehci, port_status, status_reg);
 
        } else
                ehci_dbg (ehci, "port %d high speed\n", index + 1);
@@ -268,22 +366,21 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
        /* port N changes (bit N)? */
        spin_lock_irqsave (&ehci->lock, flags);
        for (i = 0; i < ports; i++) {
-               temp = readl (&ehci->regs->port_status [i]);
-               if (temp & PORT_OWNER) {
-                       /* don't report this in GetPortStatus */
-                       if (temp & PORT_CSC) {
-                               temp &= ~PORT_RWC_BITS;
-                               temp |= PORT_CSC;
-                               writel (temp, &ehci->regs->port_status [i]);
-                       }
-                       continue;
-               }
+               temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
+
+               /*
+                * Return status information even for ports with OWNER set.
+                * Otherwise khubd wouldn't see the disconnect event when a
+                * high-speed device is switched over to the companion
+                * controller by the user.
+                */
+
                if (!(temp & PORT_CONNECT))
                        ehci->reset_done [i] = 0;
                if ((temp & mask) != 0
                                || ((temp & PORT_RESUME) != 0
-                                       && time_after (jiffies,
-                                               ehci->reset_done [i]))) {
+                                       && time_after_eq(jiffies,
+                                               ehci->reset_done[i]))) {
                        if (i < 7)
                            buf [0] |= 1 << (i + 1);
                        else
@@ -345,6 +442,7 @@ static int ehci_hub_control (
 ) {
        struct ehci_hcd *ehci = hcd_to_ehci (hcd);
        int             ports = HCS_N_PORTS (ehci->hcs_params);
+       u32 __iomem     *status_reg = &ehci->regs->port_status[wIndex - 1];
        u32             temp, status;
        unsigned long   flags;
        int             retval = 0;
@@ -373,18 +471,22 @@ static int ehci_hub_control (
                if (!wIndex || wIndex > ports)
                        goto error;
                wIndex--;
-               temp = readl (&ehci->regs->port_status [wIndex]);
-               if (temp & PORT_OWNER)
-                       break;
+               temp = ehci_readl(ehci, status_reg);
+
+               /*
+                * Even if OWNER is set, so the port is owned by the
+                * companion controller, khubd needs to be able to clear
+                * the port-change status bits (especially
+                * USB_PORT_FEAT_C_CONNECTION).
+                */
 
                switch (wValue) {
                case USB_PORT_FEAT_ENABLE:
-                       writel (temp & ~PORT_PE,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp & ~PORT_PE, status_reg);
                        break;
                case USB_PORT_FEAT_C_ENABLE:
-                       writel((temp & ~PORT_RWC_BITS) | PORT_PEC,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
+                                       status_reg);
                        break;
                case USB_PORT_FEAT_SUSPEND:
                        if (temp & PORT_RESET)
@@ -396,8 +498,8 @@ static int ehci_hub_control (
                                        goto error;
                                /* resume signaling for 20 msec */
                                temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
-                               writel (temp | PORT_RESUME,
-                                       &ehci->regs->port_status [wIndex]);
+                               ehci_writel(ehci, temp | PORT_RESUME,
+                                               status_reg);
                                ehci->reset_done [wIndex] = jiffies
                                                + msecs_to_jiffies (20);
                        }
@@ -407,16 +509,17 @@ static int ehci_hub_control (
                        break;
                case USB_PORT_FEAT_POWER:
                        if (HCS_PPC (ehci->hcs_params))
-                               writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
-                                       &ehci->regs->port_status [wIndex]);
+                               ehci_writel(ehci,
+                                         temp & ~(PORT_RWC_BITS | PORT_POWER),
+                                         status_reg);
                        break;
                case USB_PORT_FEAT_C_CONNECTION:
-                       writel((temp & ~PORT_RWC_BITS) | PORT_CSC,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
+                                       status_reg);
                        break;
                case USB_PORT_FEAT_C_OVER_CURRENT:
-                       writel((temp & ~PORT_RWC_BITS) | PORT_OCC,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
+                                       status_reg);
                        break;
                case USB_PORT_FEAT_C_RESET:
                        /* GetPortStatus clears reset */
@@ -424,7 +527,7 @@ static int ehci_hub_control (
                default:
                        goto error;
                }
-               readl (&ehci->regs->command);   /* unblock posted write */
+               ehci_readl(ehci, &ehci->regs->command); /* unblock posted write */
                break;
        case GetHubDescriptor:
                ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
@@ -440,7 +543,7 @@ static int ehci_hub_control (
                        goto error;
                wIndex--;
                status = 0;
-               temp = readl (&ehci->regs->port_status [wIndex]);
+               temp = ehci_readl(ehci, status_reg);
 
                // wPortChange bits
                if (temp & PORT_CSC)
@@ -451,42 +554,55 @@ static int ehci_hub_control (
                        status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
 
                /* whoever resumes must GetPortStatus to complete it!! */
-               if ((temp & PORT_RESUME)
-                               && time_after (jiffies,
-                                       ehci->reset_done [wIndex])) {
-                       status |= 1 << USB_PORT_FEAT_C_SUSPEND;
-                       ehci->reset_done [wIndex] = 0;
+               if (temp & PORT_RESUME) {
 
-                       /* stop resume signaling */
-                       temp = readl (&ehci->regs->port_status [wIndex]);
-                       writel (temp & ~(PORT_RWC_BITS | PORT_RESUME),
-                               &ehci->regs->port_status [wIndex]);
-                       retval = handshake (
-                                       &ehci->regs->port_status [wIndex],
-                                       PORT_RESUME, 0, 2000 /* 2msec */);
-                       if (retval != 0) {
-                               ehci_err (ehci, "port %d resume error %d\n",
-                                       wIndex + 1, retval);
-                               goto error;
+                       /* Remote Wakeup received? */
+                       if (!ehci->reset_done[wIndex]) {
+                               /* resume signaling for 20 msec */
+                               ehci->reset_done[wIndex] = jiffies
+                                               + msecs_to_jiffies(20);
+                               /* check the port again */
+                               mod_timer(&ehci_to_hcd(ehci)->rh_timer,
+                                               ehci->reset_done[wIndex]);
+                       }
+
+                       /* resume completed? */
+                       else if (time_after_eq(jiffies,
+                                       ehci->reset_done[wIndex])) {
+                               status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+                               ehci->reset_done[wIndex] = 0;
+
+                               /* stop resume signaling */
+                               temp = ehci_readl(ehci, status_reg);
+                               ehci_writel(ehci,
+                                       temp & ~(PORT_RWC_BITS | PORT_RESUME),
+                                       status_reg);
+                               retval = handshake(ehci, status_reg,
+                                          PORT_RESUME, 0, 2000 /* 2msec */);
+                               if (retval != 0) {
+                                       ehci_err(ehci,
+                                               "port %d resume error %d\n",
+                                               wIndex + 1, retval);
+                                       goto error;
+                               }
+                               temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
                        }
-                       temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
                }
 
                /* whoever resets must GetPortStatus to complete it!! */
                if ((temp & PORT_RESET)
-                               && time_after (jiffies,
-                                       ehci->reset_done [wIndex])) {
+                               && time_after_eq(jiffies,
+                                       ehci->reset_done[wIndex])) {
                        status |= 1 << USB_PORT_FEAT_C_RESET;
                        ehci->reset_done [wIndex] = 0;
 
                        /* force reset to complete */
-                       writel (temp & ~(PORT_RWC_BITS | PORT_RESET),
-                                       &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
+                                       status_reg);
                        /* REVISIT:  some hardware needs 550+ usec to clear
                         * this bit; seems too long to spin routinely...
                         */
-                       retval = handshake (
-                                       &ehci->regs->port_status [wIndex],
+                       retval = handshake(ehci, status_reg,
                                        PORT_RESET, 0, 750);
                        if (retval != 0) {
                                ehci_err (ehci, "port %d reset error %d\n",
@@ -495,28 +611,41 @@ static int ehci_hub_control (
                        }
 
                        /* see what we found out */
-                       temp = check_reset_complete (ehci, wIndex,
-                               readl (&ehci->regs->port_status [wIndex]));
+                       temp = check_reset_complete (ehci, wIndex, status_reg,
+                                       ehci_readl(ehci, status_reg));
                }
 
-               // don't show wPortStatus if it's owned by a companion hc
-               if (!(temp & PORT_OWNER)) {
-                       if (temp & PORT_CONNECT) {
-                               status |= 1 << USB_PORT_FEAT_CONNECTION;
-                               // status may be from integrated TT
-                               status |= ehci_port_speed(ehci, temp);
-                       }
-                       if (temp & PORT_PE)
-                               status |= 1 << USB_PORT_FEAT_ENABLE;
-                       if (temp & (PORT_SUSPEND|PORT_RESUME))
-                               status |= 1 << USB_PORT_FEAT_SUSPEND;
-                       if (temp & PORT_OC)
-                               status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
-                       if (temp & PORT_RESET)
-                               status |= 1 << USB_PORT_FEAT_RESET;
-                       if (temp & PORT_POWER)
-                               status |= 1 << USB_PORT_FEAT_POWER;
+               /* transfer dedicated ports to the companion hc */
+               if ((temp & PORT_CONNECT) &&
+                               test_bit(wIndex, &ehci->companion_ports)) {
+                       temp &= ~PORT_RWC_BITS;
+                       temp |= PORT_OWNER;
+                       ehci_writel(ehci, temp, status_reg);
+                       ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1);
+                       temp = ehci_readl(ehci, status_reg);
+               }
+
+               /*
+                * Even if OWNER is set, there's no harm letting khubd
+                * see the wPortStatus values (they should all be 0 except
+                * for PORT_POWER anyway).
+                */
+
+               if (temp & PORT_CONNECT) {
+                       status |= 1 << USB_PORT_FEAT_CONNECTION;
+                       // status may be from integrated TT
+                       status |= ehci_port_speed(ehci, temp);
                }
+               if (temp & PORT_PE)
+                       status |= 1 << USB_PORT_FEAT_ENABLE;
+               if (temp & (PORT_SUSPEND|PORT_RESUME))
+                       status |= 1 << USB_PORT_FEAT_SUSPEND;
+               if (temp & PORT_OC)
+                       status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+               if (temp & PORT_RESET)
+                       status |= 1 << USB_PORT_FEAT_RESET;
+               if (temp & PORT_POWER)
+                       status |= 1 << USB_PORT_FEAT_POWER;
 
 #ifndef        EHCI_VERBOSE_DEBUG
        if (status & ~0xffff)   /* only if wPortChange is interesting */
@@ -541,7 +670,7 @@ static int ehci_hub_control (
                if (!wIndex || wIndex > ports)
                        goto error;
                wIndex--;
-               temp = readl (&ehci->regs->port_status [wIndex]);
+               temp = ehci_readl(ehci, status_reg);
                if (temp & PORT_OWNER)
                        break;
 
@@ -555,13 +684,12 @@ static int ehci_hub_control (
                                goto error;
                        if (device_may_wakeup(&hcd->self.root_hub->dev))
                                temp |= PORT_WAKE_BITS;
-                       writel (temp | PORT_SUSPEND,
-                               &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
                        break;
                case USB_PORT_FEAT_POWER:
                        if (HCS_PPC (ehci->hcs_params))
-                               writel (temp | PORT_POWER,
-                                       &ehci->regs->port_status [wIndex]);
+                               ehci_writel(ehci, temp | PORT_POWER,
+                                               status_reg);
                        break;
                case USB_PORT_FEAT_RESET:
                        if (temp & PORT_RESUME)
@@ -589,7 +717,7 @@ static int ehci_hub_control (
                                ehci->reset_done [wIndex] = jiffies
                                                + msecs_to_jiffies (50);
                        }
-                       writel (temp, &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp, status_reg);
                        break;
 
                /* For downstream facing ports (these):  one hub port is put
@@ -604,13 +732,13 @@ static int ehci_hub_control (
                        ehci_quiesce(ehci);
                        ehci_halt(ehci);
                        temp |= selector << 16;
-                       writel (temp, &ehci->regs->port_status [wIndex]);
+                       ehci_writel(ehci, temp, status_reg);
                        break;
 
                default:
                        goto error;
                }
-               readl (&ehci->regs->command);   /* unblock posted writes */
+               ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
                break;
 
        default:
index 4bc7970..12edc72 100644 (file)
@@ -38,7 +38,7 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
                if ((temp & (3 << 13)) == (1 << 13)) {
                        temp &= 0x1fff;
                        ehci->debug = ehci_to_hcd(ehci)->regs + temp;
-                       temp = readl(&ehci->debug->control);
+                       temp = ehci_readl(ehci, &ehci->debug->control);
                        ehci_info(ehci, "debug port %d%s\n",
                                HCS_DEBUG_PORT(ehci->hcs_params),
                                (temp & DBGP_ENABLED)
@@ -71,8 +71,24 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
        u32                     temp;
        int                     retval;
 
+       switch (pdev->vendor) {
+       case PCI_VENDOR_ID_TOSHIBA_2:
+               /* celleb's companion chip */
+               if (pdev->device == 0x01b5) {
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+                       ehci->big_endian_mmio = 1;
+#else
+                       ehci_warn(ehci,
+                                 "unsupported big endian Toshiba quirk\n");
+#endif
+               }
+               break;
+       }
+
        ehci->caps = hcd->regs;
-       ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+       ehci->regs = hcd->regs +
+               HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
        dbg_hcs_params(ehci, "reset");
        dbg_hcc_params(ehci, "reset");
 
@@ -101,7 +117,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
        }
 
        /* cache this readonly data; minimize chip reads */
-       ehci->hcs_params = readl(&ehci->caps->hcs_params);
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
        retval = ehci_halt(ehci);
        if (retval)
@@ -235,8 +251,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
                rc = -EINVAL;
                goto bail;
        }
-       writel (0, &ehci->regs->intr_enable);
-       (void)readl(&ehci->regs->intr_enable);
+       ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+       (void)ehci_readl(ehci, &ehci->regs->intr_enable);
 
        /* make sure snapshot being resumed re-enumerates everything */
        if (message.event == PM_EVENT_PRETHAW) {
@@ -270,13 +286,13 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
        /* If CF is still set, we maintained PCI Vaux power.
         * Just undo the effect of ehci_pci_suspend().
         */
-       if (readl(&ehci->regs->configured_flag) == FLAG_CF) {
+       if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
                int     mask = INTR_MASK;
 
                if (!device_may_wakeup(&hcd->self.root_hub->dev))
                        mask &= ~STS_PCD;
-               writel(mask, &ehci->regs->intr_enable);
-               readl(&ehci->regs->intr_enable);
+               ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+               ehci_readl(ehci, &ehci->regs->intr_enable);
                return 0;
        }
 
@@ -300,9 +316,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
        /* here we "know" root ports should always stay powered */
        ehci_port_power(ehci, 1);
 
-       writel(ehci->command, &ehci->regs->command);
-       writel(FLAG_CF, &ehci->regs->configured_flag);
-       readl(&ehci->regs->command);    /* unblock posted writes */
+       ehci_writel(ehci, ehci->command, &ehci->regs->command);
+       ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+       ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
 
        hcd->state = HC_STATE_SUSPENDED;
        return 0;
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
new file mode 100644 (file)
index 0000000..371f194
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ *  PS3 EHCI Host Controller driver
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 Sony Corp.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  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 <asm/ps3.h>
+
+static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
+{
+       int result;
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+       ehci->big_endian_mmio = 1;
+
+       ehci->caps = hcd->regs;
+       ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+               &ehci->caps->hc_capbase));
+
+       dbg_hcs_params(ehci, "reset");
+       dbg_hcc_params(ehci, "reset");
+
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+       result = ehci_halt(ehci);
+
+       if (result)
+               return result;
+
+       result = ehci_init(hcd);
+
+       if (result)
+               return result;
+
+       ehci_port_power(ehci, 0);
+
+       return result;
+}
+
+static const struct hc_driver ps3_ehci_hc_driver = {
+       .description            = hcd_name,
+       .product_desc           = "PS3 EHCI Host Controller",
+       .hcd_priv_size          = sizeof(struct ehci_hcd),
+       .irq                    = ehci_irq,
+       .flags                  = HCD_MEMORY | HCD_USB2,
+       .reset                  = ps3_ehci_hc_reset,
+       .start                  = ehci_run,
+       .stop                   = ehci_stop,
+       .shutdown               = ehci_shutdown,
+       .urb_enqueue            = ehci_urb_enqueue,
+       .urb_dequeue            = ehci_urb_dequeue,
+       .endpoint_disable       = ehci_endpoint_disable,
+       .get_frame_number       = ehci_get_frame,
+       .hub_status_data        = ehci_hub_status_data,
+       .hub_control            = ehci_hub_control,
+#if defined(CONFIG_PM)
+       .bus_suspend            = ehci_bus_suspend,
+       .bus_resume             = ehci_bus_resume,
+#endif
+};
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+       const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+
+static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+{
+       int result;
+       struct usb_hcd *hcd;
+       unsigned int virq;
+       static u64 dummy_mask = DMA_32BIT_MASK;
+
+       if (usb_disabled()) {
+               result = -ENODEV;
+               goto fail_start;
+       }
+
+       result = ps3_mmio_region_create(dev->m_region);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+                       __func__, __LINE__);
+               result = -EPERM;
+               goto fail_mmio;
+       }
+
+       dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+               __LINE__, dev->m_region->lpar_addr);
+
+       result = ps3_alloc_io_irq(dev->interrupt_id, &virq);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+                       __func__, __LINE__, virq);
+               result = -EPERM;
+               goto fail_irq;
+       }
+
+       dev->core.power.power_state = PMSG_ON;
+       dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+       hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id);
+
+       if (!hcd) {
+               dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+                       __LINE__);
+               result = -ENOMEM;
+               goto fail_create_hcd;
+       }
+
+       hcd->rsrc_start = dev->m_region->lpar_addr;
+       hcd->rsrc_len = dev->m_region->len;
+       hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+       if (!hcd->regs) {
+               dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+                       __LINE__);
+               result = -EPERM;
+               goto fail_ioremap;
+       }
+
+       dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+               (unsigned long)hcd->rsrc_start);
+       dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len   %lxh\n", __func__, __LINE__,
+               (unsigned long)hcd->rsrc_len);
+       dev_dbg(&dev->core, "%s:%d: hcd->regs       %lxh\n", __func__, __LINE__,
+               (unsigned long)hcd->regs);
+       dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
+               (unsigned long)virq);
+
+       ps3_system_bus_set_driver_data(dev, hcd);
+
+       result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+                       __func__, __LINE__, result);
+               goto fail_add_hcd;
+       }
+
+       return result;
+
+fail_add_hcd:
+       iounmap(hcd->regs);
+fail_ioremap:
+       usb_put_hcd(hcd);
+fail_create_hcd:
+       ps3_free_io_irq(virq);
+fail_irq:
+       ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+       return result;
+}
+
+static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
+{
+       struct usb_hcd *hcd =
+               (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+       usb_put_hcd(hcd);
+       ps3_system_bus_set_driver_data(dev, NULL);
+
+       return 0;
+}
+
+MODULE_ALIAS("ps3-ehci");
+
+static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
+       .match_id = PS3_MATCH_ID_EHCI,
+       .core = {
+               .name = "ps3-ehci-driver",
+       },
+       .probe = ps3_ehci_sb_probe,
+       .remove = ps3_ehci_sb_remove,
+};
index 62e46dc..e7fbbd0 100644 (file)
@@ -789,13 +789,14 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
        head = ehci->async;
        timer_action_done (ehci, TIMER_ASYNC_OFF);
        if (!head->qh_next.qh) {
-               u32     cmd = readl (&ehci->regs->command);
+               u32     cmd = ehci_readl(ehci, &ehci->regs->command);
 
                if (!(cmd & CMD_ASE)) {
                        /* in case a clear of CMD_ASE didn't take yet */
-                       (void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
+                       (void)handshake(ehci, &ehci->regs->status,
+                                       STS_ASS, 0, 150);
                        cmd |= CMD_ASE | CMD_RUN;
-                       writel (cmd, &ehci->regs->command);
+                       ehci_writel(ehci, cmd, &ehci->regs->command);
                        ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
                        /* posted write need not be known to HC yet ... */
                }
@@ -1007,7 +1008,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
 
 static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-       int             cmd = readl (&ehci->regs->command);
+       int             cmd = ehci_readl(ehci, &ehci->regs->command);
        struct ehci_qh  *prev;
 
 #ifdef DEBUG
@@ -1025,7 +1026,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
                if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
                                && !ehci->reclaim) {
                        /* ... and CMD_IAAD clear */
-                       writel (cmd & ~CMD_ASE, &ehci->regs->command);
+                       ehci_writel(ehci, cmd & ~CMD_ASE,
+                                   &ehci->regs->command);
                        wmb ();
                        // handshake later, if we need to
                        timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -1054,8 +1056,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
        ehci->reclaim_ready = 0;
        cmd |= CMD_IAAD;
-       writel (cmd, &ehci->regs->command);
-       (void) readl (&ehci->regs->command);
+       ehci_writel(ehci, cmd, &ehci->regs->command);
+       (void)ehci_readl(ehci, &ehci->regs->command);
        timer_action (ehci, TIMER_IAA_WATCHDOG);
 }
 
index 65c402a..7b5ae71 100644 (file)
@@ -433,20 +433,20 @@ static int enable_periodic (struct ehci_hcd *ehci)
        /* did clearing PSE did take effect yet?
         * takes effect only at frame boundaries...
         */
-       status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
+       status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125);
        if (status != 0) {
                ehci_to_hcd(ehci)->state = HC_STATE_HALT;
                return status;
        }
 
-       cmd = readl (&ehci->regs->command) | CMD_PSE;
-       writel (cmd, &ehci->regs->command);
+       cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
+       ehci_writel(ehci, cmd, &ehci->regs->command);
        /* posted write ... PSS happens later */
        ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 
        /* make sure ehci_work scans these */
-       ehci->next_uframe = readl (&ehci->regs->frame_index)
-                               % (ehci->periodic_size << 3);
+       ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
+               % (ehci->periodic_size << 3);
        return 0;
 }
 
@@ -458,14 +458,14 @@ static int disable_periodic (struct ehci_hcd *ehci)
        /* did setting PSE not take effect yet?
         * takes effect only at frame boundaries...
         */
-       status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
+       status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
        if (status != 0) {
                ehci_to_hcd(ehci)->state = HC_STATE_HALT;
                return status;
        }
 
-       cmd = readl (&ehci->regs->command) & ~CMD_PSE;
-       writel (cmd, &ehci->regs->command);
+       cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
+       ehci_writel(ehci, cmd, &ehci->regs->command);
        /* posted write ... */
 
        ehci->next_uframe = -1;
@@ -1336,7 +1336,7 @@ iso_stream_schedule (
                goto fail;
        }
 
-       now = readl (&ehci->regs->frame_index) % mod;
+       now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
 
        /* when's the last uframe this urb could start? */
        max = now + mod;
@@ -2088,7 +2088,7 @@ scan_periodic (struct ehci_hcd *ehci)
         */
        now_uframe = ehci->next_uframe;
        if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
-               clock = readl (&ehci->regs->frame_index);
+               clock = ehci_readl(ehci, &ehci->regs->frame_index);
        else
                clock = now_uframe + mod - 1;
        clock %= mod;
@@ -2213,7 +2213,7 @@ restart:
                        if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
                                break;
                        ehci->next_uframe = now_uframe;
-                       now = readl (&ehci->regs->frame_index) % mod;
+                       now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
                        if (now_uframe == now)
                                break;
 
index 74dbc6c..ec0da03 100644 (file)
@@ -74,7 +74,11 @@ struct ehci_hcd {                    /* one per controller */
 
        /* per root hub port */
        unsigned long           reset_done [EHCI_MAX_ROOT_PORTS];
-       unsigned long           bus_suspended;
+       /* bit vectors (one bit per port) */
+       unsigned long           bus_suspended;          /* which ports were
+                       already suspended at the start of a bus suspend */
+       unsigned long           companion_ports;        /* which ports are
+                       dedicated to the companion controller */
 
        /* per-HC memory pools (could be per-bus, but ...) */
        struct dma_pool         *qh_pool;       /* qh per active urb */
@@ -92,6 +96,7 @@ struct ehci_hcd {                     /* one per controller */
        unsigned                is_tdi_rh_tt:1; /* TDI roothub with TT */
        unsigned                no_selective_suspend:1;
        unsigned                has_fsl_port_bug:1; /* FreeScale */
+       unsigned                big_endian_mmio:1;
 
        u8                      sbrn;           /* packed release number */
 
@@ -651,6 +656,45 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
 #define        ehci_has_fsl_portno_bug(e)              (0)
 #endif
 
+/*
+ * While most USB host controllers implement their registers in
+ * little-endian format, a minority (celleb companion chip) implement
+ * them in big endian format.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ */
+
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+#define ehci_big_endian_mmio(e)                ((e)->big_endian_mmio)
+#else
+#define ehci_big_endian_mmio(e)                0
+#endif
+
+static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
+                                      __u32 __iomem * regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+       return ehci_big_endian_mmio(ehci) ?
+               readl_be((__force u32 *)regs) :
+               readl((__force u32 *)regs);
+#else
+       return readl((__force u32 *)regs);
+#endif
+}
+
+static inline void ehci_writel (const struct ehci_hcd *ehci,
+                               const unsigned int val, __u32 __iomem *regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+       ehci_big_endian_mmio(ehci) ?
+               writel_be(val, (__force u32 *)regs) :
+               writel(val, (__force u32 *)regs);
+#else
+       writel(val, (__force u32 *)regs);
+#endif
+}
 
 /*-------------------------------------------------------------------------*/
 
index cc40551..9303464 100644 (file)
@@ -170,7 +170,6 @@ static int usb_hcd_at91_remove(struct usb_hcd *hcd,
        at91_stop_hc(pdev);
        iounmap(hcd->regs);
        release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-       disable_irq_wake(hcd->irq);
 
        clk_put(fclk);
        clk_put(iclk);
@@ -271,8 +270,6 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
 
        if (device_may_wakeup(&pdev->dev))
                enable_irq_wake(hcd->irq);
-       else
-               disable_irq_wake(hcd->irq);
 
        /*
         * The integrated transceivers seem unable to notice disconnect,
@@ -293,6 +290,11 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
 
 static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
 {
+       struct usb_hcd  *hcd = platform_get_drvdata(pdev);
+
+       if (device_may_wakeup(&pdev->dev))
+               disable_irq_wake(hcd->irq);
+
        if (!clocked) {
                clk_enable(iclk);
                clk_enable(fclk);
@@ -320,18 +322,3 @@ static struct platform_driver ohci_hcd_at91_driver = {
        },
 };
 
-static int __init ohci_hcd_at91_init (void)
-{
-       if (usb_disabled())
-               return -ENODEV;
-
-       return platform_driver_register(&ohci_hcd_at91_driver);
-}
-
-static void __exit ohci_hcd_at91_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_at91_driver);
-}
-
-module_init (ohci_hcd_at91_init);
-module_exit (ohci_hcd_at91_cleanup);
index e70b243..663a060 100644 (file)
@@ -345,19 +345,3 @@ static struct platform_driver ohci_hcd_au1xxx_driver = {
        },
 };
 
-static int __init ohci_hcd_au1xxx_init (void)
-{
-       pr_debug (DRIVER_INFO " (Au1xxx)");
-       pr_debug ("block sizes: ed %d td %d\n",
-               sizeof (struct ed), sizeof (struct td));
-
-       return platform_driver_register(&ohci_hcd_au1xxx_driver);
-}
-
-static void __exit ohci_hcd_au1xxx_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_au1xxx_driver);
-}
-
-module_init (ohci_hcd_au1xxx_init);
-module_exit (ohci_hcd_au1xxx_cleanup);
index 3348b07..44c60fb 100644 (file)
@@ -214,15 +214,3 @@ static struct platform_driver ohci_hcd_ep93xx_driver = {
        },
 };
 
-static int __init ohci_hcd_ep93xx_init(void)
-{
-       return platform_driver_register(&ohci_hcd_ep93xx_driver);
-}
-
-static void __exit ohci_hcd_ep93xx_cleanup(void)
-{
-       platform_driver_unregister(&ohci_hcd_ep93xx_driver);
-}
-
-module_init(ohci_hcd_ep93xx_init);
-module_exit(ohci_hcd_ep93xx_cleanup);
index c1c1d87..fa6a7ce 100644 (file)
@@ -855,63 +855,167 @@ MODULE_LICENSE ("GPL");
 
 #ifdef CONFIG_PCI
 #include "ohci-pci.c"
+#define PCI_DRIVER             ohci_pci_driver
 #endif
 
 #ifdef CONFIG_SA1111
 #include "ohci-sa1111.c"
+#define SA1111_DRIVER          ohci_hcd_sa1111_driver
 #endif
 
 #ifdef CONFIG_ARCH_S3C2410
 #include "ohci-s3c2410.c"
+#define PLATFORM_DRIVER                ohci_hcd_s3c2410_driver
 #endif
 
 #ifdef CONFIG_ARCH_OMAP
 #include "ohci-omap.c"
+#define PLATFORM_DRIVER                ohci_hcd_omap_driver
 #endif
 
 #ifdef CONFIG_ARCH_LH7A404
 #include "ohci-lh7a404.c"
+#define PLATFORM_DRIVER                ohci_hcd_lh7a404_driver
 #endif
 
 #ifdef CONFIG_PXA27x
 #include "ohci-pxa27x.c"
+#define PLATFORM_DRIVER                ohci_hcd_pxa27x_driver
 #endif
 
 #ifdef CONFIG_ARCH_EP93XX
 #include "ohci-ep93xx.c"
+#define PLATFORM_DRIVER                ohci_hcd_ep93xx_driver
 #endif
 
 #ifdef CONFIG_SOC_AU1X00
 #include "ohci-au1xxx.c"
+#define PLATFORM_DRIVER                ohci_hcd_au1xxx_driver
 #endif
 
 #ifdef CONFIG_PNX8550
 #include "ohci-pnx8550.c"
+#define PLATFORM_DRIVER                ohci_hcd_pnx8550_driver
 #endif
 
 #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
 #include "ohci-ppc-soc.c"
+#define PLATFORM_DRIVER                ohci_hcd_ppc_soc_driver
 #endif
 
 #ifdef CONFIG_ARCH_AT91
 #include "ohci-at91.c"
+#define PLATFORM_DRIVER                ohci_hcd_at91_driver
 #endif
 
 #ifdef CONFIG_ARCH_PNX4008
 #include "ohci-pnx4008.c"
+#define PLATFORM_DRIVER                usb_hcd_pnx4008_driver
 #endif
 
-#if !(defined(CONFIG_PCI) \
-      || defined(CONFIG_SA1111) \
-      || defined(CONFIG_ARCH_S3C2410) \
-      || defined(CONFIG_ARCH_OMAP) \
-      || defined (CONFIG_ARCH_LH7A404) \
-      || defined (CONFIG_PXA27x) \
-      || defined (CONFIG_ARCH_EP93XX) \
-      || defined (CONFIG_SOC_AU1X00) \
-      || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
-      || defined (CONFIG_ARCH_AT91) \
-      || defined (CONFIG_ARCH_PNX4008) \
-       )
+
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
+#include "ohci-ppc-of.c"
+#define OF_PLATFORM_DRIVER     ohci_hcd_ppc_of_driver
+#endif
+
+#ifdef CONFIG_PPC_PS3
+#include "ohci-ps3.c"
+#define PS3_SYSTEM_BUS_DRIVER  ps3_ohci_sb_driver
+#endif
+
+#if    !defined(PCI_DRIVER) &&         \
+       !defined(PLATFORM_DRIVER) &&    \
+       !defined(OF_PLATFORM_DRIVER) && \
+       !defined(SA1111_DRIVER) &&      \
+       !defined(PS3_SYSTEM_BUS_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
+
+static int __init ohci_hcd_mod_init(void)
+{
+       int retval = 0;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name);
+       pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+               sizeof (struct ed), sizeof (struct td));
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+       if (retval < 0)
+               goto error_ps3;
+#endif
+
+#ifdef PLATFORM_DRIVER
+       retval = platform_driver_register(&PLATFORM_DRIVER);
+       if (retval < 0)
+               goto error_platform;
+#endif
+
+#ifdef OF_PLATFORM_DRIVER
+       retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
+       if (retval < 0)
+               goto error_of_platform;
+#endif
+
+#ifdef SA1111_DRIVER
+       retval = sa1111_driver_register(&SA1111_DRIVER);
+       if (retval < 0)
+               goto error_sa1111;
+#endif
+
+#ifdef PCI_DRIVER
+       retval = pci_register_driver(&PCI_DRIVER);
+       if (retval < 0)
+               goto error_pci;
+#endif
+
+       return retval;
+
+       /* Error path */
+#ifdef PCI_DRIVER
+ error_pci:
+#endif
+#ifdef SA1111_DRIVER
+       sa1111_driver_unregister(&SA1111_DRIVER);
+ error_sa1111:
+#endif
+#ifdef OF_PLATFORM_DRIVER
+       of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+ error_of_platform:
+#endif
+#ifdef PLATFORM_DRIVER
+       platform_driver_unregister(&PLATFORM_DRIVER);
+ error_platform:
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ error_ps3:
+#endif
+       return retval;
+}
+module_init(ohci_hcd_mod_init);
+
+static void __exit ohci_hcd_mod_exit(void)
+{
+#ifdef PCI_DRIVER
+       pci_unregister_driver(&PCI_DRIVER);
+#endif
+#ifdef SA1111_DRIVER
+       sa1111_driver_unregister(&SA1111_DRIVER);
+#endif
+#ifdef OF_PLATFORM_DRIVER
+       of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+#endif
+#ifdef PLATFORM_DRIVER
+       platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+       ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
+}
+module_exit(ohci_hcd_mod_exit);
+
index e9807cf..4a043ab 100644 (file)
@@ -251,19 +251,3 @@ static struct platform_driver ohci_hcd_lh7a404_driver = {
        },
 };
 
-static int __init ohci_hcd_lh7a404_init (void)
-{
-       pr_debug (DRIVER_INFO " (LH7A404)");
-       pr_debug ("block sizes: ed %d td %d\n",
-               sizeof (struct ed), sizeof (struct td));
-
-       return platform_driver_register(&ohci_hcd_lh7a404_driver);
-}
-
-static void __exit ohci_hcd_lh7a404_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_lh7a404_driver);
-}
-
-module_init (ohci_hcd_lh7a404_init);
-module_exit (ohci_hcd_lh7a404_cleanup);
index 27be1f9..5cfa3d1 100644 (file)
@@ -544,22 +544,3 @@ static struct platform_driver ohci_hcd_omap_driver = {
        },
 };
 
-static int __init ohci_hcd_omap_init (void)
-{
-       printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name);
-       if (usb_disabled())
-               return -ENODEV;
-
-       pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
-               sizeof (struct ed), sizeof (struct td));
-
-       return platform_driver_register(&ohci_hcd_omap_driver);
-}
-
-static void __exit ohci_hcd_omap_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_omap_driver);
-}
-
-module_init (ohci_hcd_omap_init);
-module_exit (ohci_hcd_omap_cleanup);
index 596e0b4..b331ac4 100644 (file)
 
 /*-------------------------------------------------------------------------*/
 
-static int
-ohci_pci_reset (struct usb_hcd *hcd)
+/* AMD 756, for most chips (early revs), corrupts register
+ * values on read ... so enable the vendor workaround.
+ */
+static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
 
-       ohci_hcd_init (ohci);
-       return ohci_init (ohci);
+       ohci->flags = OHCI_QUIRK_AMD756;
+       ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
+
+       /* also erratum 10 (suspend/resume issues) */
+       device_init_wakeup(&hcd->self.root_hub->dev, 0);
+
+       return 0;
 }
 
-static int __devinit
-ohci_pci_start (struct usb_hcd *hcd)
+/* Apple's OHCI driver has a lot of bizarre workarounds
+ * for this chip.  Evidently control and bulk lists
+ * can get confused.  (B&W G3 models, and ...)
+ */
+static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
 {
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
-       int             ret;
 
-       /* REVISIT this whole block should move to reset(), which handles
-        * all the other one-time init.
+       ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n");
+
+       return 0;
+}
+
+/* Check for NSC87560. We have to look at the bridge (fn1) to
+ * identify the USB (fn2). This quirk might apply to more or
+ * even all NSC stuff.
+ */
+static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
+{
+       struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+       struct pci_dev  *b;
+
+       b  = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
+       if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
+           && b->vendor == PCI_VENDOR_ID_NS) {
+               struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+               ohci->flags |= OHCI_QUIRK_SUPERIO;
+               ohci_dbg (ohci, "Using NSC SuperIO setup\n");
+       }
+       pci_dev_put(b);
+
+       return 0;
+}
+
+/* Check for Compaq's ZFMicro chipset, which needs short
+ * delays before control or bulk queues get re-activated
+ * in finish_unlinks()
+ */
+static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+       ohci->flags |= OHCI_QUIRK_ZFMICRO;
+       ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+
+       return 0;
+}
+
+/* Check for Toshiba SCC OHCI which has big endian registers
+ * and little endian in memory data structures
+ */
+static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+
+       /* That chip is only present in the southbridge of some
+        * cell based platforms which are supposed to select
+        * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if
+        * that was the case though.
+        */
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+       ohci->flags |= OHCI_QUIRK_BE_MMIO;
+       ohci_dbg (ohci, "enabled big endian Toshiba quirk\n");
+       return 0;
+#else
+       ohci_err (ohci, "unsupported big endian Toshiba quirk\n");
+       return -ENXIO;
+#endif
+}
+
+/* List of quirks for OHCI */
+static const struct pci_device_id ohci_pci_quirks[] = {
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c),
+               .driver_data = (unsigned long)ohci_quirk_amd756,
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861),
+               .driver_data = (unsigned long)ohci_quirk_opti,
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID),
+               .driver_data = (unsigned long)ohci_quirk_ns,
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8),
+               .driver_data = (unsigned long)ohci_quirk_zfmicro,
+       },
+       {
+               PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
+               .driver_data = (unsigned long)ohci_quirk_toshiba_scc,
+       },
+       /* FIXME for some of the early AMD 760 southbridges, OHCI
+        * won't work at all.  blacklist them.
         */
+
+       {},
+};
+
+static int ohci_pci_reset (struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+       int ret = 0;
+
        if (hcd->self.controller) {
                struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+               const struct pci_device_id *quirk_id;
 
-               /* AMD 756, for most chips (early revs), corrupts register
-                * values on read ... so enable the vendor workaround.
-                */
-               if (pdev->vendor == PCI_VENDOR_ID_AMD
-                               && pdev->device == 0x740c) {
-                       ohci->flags = OHCI_QUIRK_AMD756;
-                       ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
-                       /* also erratum 10 (suspend/resume issues) */
-                       device_init_wakeup(&hcd->self.root_hub->dev, 0);
+               quirk_id = pci_match_id(ohci_pci_quirks, pdev);
+               if (quirk_id != NULL) {
+                       int (*quirk)(struct usb_hcd *ohci);
+                       quirk = (void *)quirk_id->driver_data;
+                       ret = quirk(hcd);
                }
+       }
+       if (ret == 0) {
+               ohci_hcd_init (ohci);
+               return ohci_init (ohci);
+       }
+       return ret;
+}
 
-               /* FIXME for some of the early AMD 760 southbridges, OHCI
-                * won't work at all.  blacklist them.
-                */
-
-               /* Apple's OHCI driver has a lot of bizarre workarounds
-                * for this chip.  Evidently control and bulk lists
-                * can get confused.  (B&W G3 models, and ...)
-                */
-               else if (pdev->vendor == PCI_VENDOR_ID_OPTI
-                               && pdev->device == 0xc861) {
-                       ohci_dbg (ohci,
-                               "WARNING: OPTi workarounds unavailable\n");
-               }
 
-               /* Check for NSC87560. We have to look at the bridge (fn1) to
-                * identify the USB (fn2). This quirk might apply to more or
-                * even all NSC stuff.
-                */
-               else if (pdev->vendor == PCI_VENDOR_ID_NS) {
-                       struct pci_dev  *b;
-
-                       b  = pci_get_slot (pdev->bus,
-                                       PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
-                       if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
-                                       && b->vendor == PCI_VENDOR_ID_NS) {
-                               ohci->flags |= OHCI_QUIRK_SUPERIO;
-                               ohci_dbg (ohci, "Using NSC SuperIO setup\n");
-                       }
-                       pci_dev_put(b);
-               }
+static int __devinit ohci_pci_start (struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+       int             ret;
 
-               /* Check for Compaq's ZFMicro chipset, which needs short
-                * delays before control or bulk queues get re-activated
-                * in finish_unlinks()
-                */
-               else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ
-                               && pdev->device  == 0xa0f8) {
-                       ohci->flags |= OHCI_QUIRK_ZFMICRO;
-                       ohci_dbg (ohci,
-                               "enabled Compaq ZFMicro chipset quirk\n");
-               }
+#ifdef CONFIG_PM /* avoid warnings about unused pdev */
+       if (hcd->self.controller) {
+               struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
                /* RWC may not be set for add-in PCI cards, since boot
                 * firmware probably ignored them.  This transfers PCI
@@ -101,16 +176,14 @@ ohci_pci_start (struct usb_hcd *hcd)
                if (device_may_wakeup(&pdev->dev))
                        ohci->hc_control |= OHCI_CTRL_RWC;
        }
+#endif /* CONFIG_PM */
 
-       /* NOTE: there may have already been a first reset, to
-        * keep bios/smm irqs from making trouble
-        */
-       if ((ret = ohci_run (ohci)) < 0) {
+       ret = ohci_run (ohci);
+       if (ret < 0) {
                ohci_err (ohci, "can't start\n");
                ohci_stop (hcd);
-               return ret;
        }
-       return 0;
+       return ret;
 }
 
 #ifdef CONFIG_PM
@@ -238,23 +311,3 @@ static struct pci_driver ohci_pci_driver = {
        .shutdown =     usb_hcd_pci_shutdown,
 };
 
-
-static int __init ohci_hcd_pci_init (void)
-{
-       printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
-       if (usb_disabled())
-               return -ENODEV;
-
-       pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
-               sizeof (struct ed), sizeof (struct td));
-       return pci_register_driver (&ohci_pci_driver);
-}
-module_init (ohci_hcd_pci_init);
-
-/*-------------------------------------------------------------------------*/
-
-static void __exit ohci_hcd_pci_cleanup (void)
-{
-       pci_unregister_driver (&ohci_pci_driver);
-}
-module_exit (ohci_hcd_pci_cleanup);
index 3a8cbfb..893b172 100644 (file)
@@ -465,15 +465,3 @@ static struct platform_driver usb_hcd_pnx4008_driver = {
        .remove = usb_hcd_pnx4008_remove,
 };
 
-static int __init usb_hcd_pnx4008_init(void)
-{
-       return platform_driver_register(&usb_hcd_pnx4008_driver);
-}
-
-static void __exit usb_hcd_pnx4008_cleanup(void)
-{
-       return platform_driver_unregister(&usb_hcd_pnx4008_driver);
-}
-
-module_init(usb_hcd_pnx4008_init);
-module_exit(usb_hcd_pnx4008_cleanup);
index 6922b91..de45eb0 100644 (file)
@@ -240,19 +240,3 @@ static struct platform_driver ohci_hcd_pnx8550_driver = {
        .remove         = ohci_hcd_pnx8550_drv_remove,
 };
 
-static int __init ohci_hcd_pnx8550_init (void)
-{
-       pr_debug (DRIVER_INFO " (pnx8550)");
-       pr_debug ("block sizes: ed %d td %d\n",
-               sizeof (struct ed), sizeof (struct td));
-
-       return platform_driver_register(&ohci_hcd_pnx8550_driver);
-}
-
-static void __exit ohci_hcd_pnx8550_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_pnx8550_driver);
-}
-
-module_init (ohci_hcd_pnx8550_init);
-module_exit (ohci_hcd_pnx8550_cleanup);
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
new file mode 100644 (file)
index 0000000..08e237c
--- /dev/null
@@ -0,0 +1,232 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Bus glue for OHCI HC on the of_platform bus
+ *
+ * Modified for of_platform bus from ohci-sa1111.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/signal.h>
+
+#include <asm/of_platform.h>
+#include <asm/prom.h>
+
+
+static int __devinit
+ohci_ppc_of_start(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+       int             ret;
+
+       if ((ret = ohci_init(ohci)) < 0)
+               return ret;
+
+       if ((ret = ohci_run(ohci)) < 0) {
+               err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+               ohci_stop(hcd);
+               return ret;
+       }
+
+       return 0;
+}
+
+static const struct hc_driver ohci_ppc_of_hc_driver = {
+       .description =          hcd_name,
+       .product_desc =         "OF OHCI",
+       .hcd_priv_size =        sizeof(struct ohci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq =                  ohci_irq,
+       .flags =                HCD_USB11 | HCD_MEMORY,
+
+       /*
+        * basic lifecycle operations
+        */
+       .start =                ohci_ppc_of_start,
+       .stop =                 ohci_stop,
+       .shutdown =             ohci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue =          ohci_urb_enqueue,
+       .urb_dequeue =          ohci_urb_dequeue,
+       .endpoint_disable =     ohci_endpoint_disable,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number =     ohci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data =      ohci_hub_status_data,
+       .hub_control =          ohci_hub_control,
+       .hub_irq_enable =       ohci_rhsc_enable,
+#ifdef CONFIG_PM
+       .bus_suspend =          ohci_bus_suspend,
+       .bus_resume =           ohci_bus_resume,
+#endif
+       .start_port_reset =     ohci_start_port_reset,
+};
+
+
+static int __devinit
+ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+       struct device_node *dn = op->node;
+       struct usb_hcd *hcd;
+       struct ohci_hcd *ohci;
+       struct resource res;
+       int irq;
+
+       int rv;
+       int is_bigendian;
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       is_bigendian =
+               device_is_compatible(dn, "ohci-bigendian") ||
+               device_is_compatible(dn, "ohci-be");
+
+       dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
+
+       rv = of_address_to_resource(dn, 0, &res);
+       if (rv)
+               return rv;
+
+       hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
+       if (!hcd)
+               return -ENOMEM;
+
+       hcd->rsrc_start = res.start;
+       hcd->rsrc_len = res.end - res.start + 1;
+
+       if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+               printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+               rv = -EBUSY;
+               goto err_rmr;
+       }
+
+       irq = irq_of_parse_and_map(dn, 0);
+       if (irq == NO_IRQ) {
+               printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+               rv = -EBUSY;
+               goto err_irq;
+       }
+
+       hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+       if (!hcd->regs) {
+               printk(KERN_ERR __FILE__ ": ioremap failed\n");
+               rv = -ENOMEM;
+               goto err_ioremap;
+       }
+
+       ohci = hcd_to_ohci(hcd);
+       if (is_bigendian)
+               ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+       ohci_hcd_init(ohci);
+
+       rv = usb_add_hcd(hcd, irq, 0);
+       if (rv == 0)
+               return 0;
+
+       iounmap(hcd->regs);
+err_ioremap:
+       irq_dispose_mapping(irq);
+err_irq:
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+       usb_put_hcd(hcd);
+
+       return rv;
+}
+
+static int ohci_hcd_ppc_of_remove(struct of_device *op)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+       dev_set_drvdata(&op->dev, NULL);
+
+       dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
+
+       usb_remove_hcd(hcd);
+
+       iounmap(hcd->regs);
+       irq_dispose_mapping(hcd->irq);
+       release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+       usb_put_hcd(hcd);
+
+       return 0;
+}
+
+static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+        if (hcd->driver->shutdown)
+                hcd->driver->shutdown(hcd);
+
+       return 0;
+}
+
+
+static struct of_device_id ohci_hcd_ppc_of_match[] = {
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
+       {
+               .name = "usb",
+               .compatible = "ohci-bigendian",
+       },
+       {
+               .name = "usb",
+               .compatible = "ohci-be",
+       },
+#endif
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
+       {
+               .name = "usb",
+               .compatible = "ohci-littledian",
+       },
+       {
+               .name = "usb",
+               .compatible = "ohci-le",
+       },
+#endif
+       {},
+};
+MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
+
+#if    !defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
+       !defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
+#error "No endianess selected for ppc-of-ohci"
+#endif
+
+
+static struct of_platform_driver ohci_hcd_ppc_of_driver = {
+       .name           = "ppc-of-ohci",
+       .match_table    = ohci_hcd_ppc_of_match,
+       .probe          = ohci_hcd_ppc_of_probe,
+       .remove         = ohci_hcd_ppc_of_remove,
+       .shutdown       = ohci_hcd_ppc_of_shutdown,
+#ifdef CONFIG_PM
+       /*.suspend      = ohci_hcd_ppc_soc_drv_suspend,*/
+       /*.resume       = ohci_hcd_ppc_soc_drv_resume,*/
+#endif
+       .driver         = {
+               .name   = "ppc-of-ohci",
+               .owner  = THIS_MODULE,
+       },
+};
+
index e1a7eb8..1a2e177 100644 (file)
@@ -72,7 +72,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
        }
 
        ohci = hcd_to_ohci(hcd);
-       ohci->flags |= OHCI_BIG_ENDIAN;
+       ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
        ohci_hcd_init(ohci);
 
        retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
@@ -208,19 +208,3 @@ static struct platform_driver ohci_hcd_ppc_soc_driver = {
        },
 };
 
-static int __init ohci_hcd_ppc_soc_init(void)
-{
-       pr_debug(DRIVER_INFO " (PPC SOC)\n");
-       pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
-                                                       sizeof(struct td));
-
-       return platform_driver_register(&ohci_hcd_ppc_soc_driver);
-}
-
-static void __exit ohci_hcd_ppc_soc_cleanup(void)
-{
-       platform_driver_unregister(&ohci_hcd_ppc_soc_driver);
-}
-
-module_init(ohci_hcd_ppc_soc_init);
-module_exit(ohci_hcd_ppc_soc_cleanup);
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
new file mode 100644 (file)
index 0000000..69d948b
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ *  PS3 OHCI Host Controller driver
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 Sony Corp.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  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 <asm/ps3.h>
+
+static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
+{
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+       ohci->flags |= OHCI_QUIRK_BE_MMIO;
+       ohci_hcd_init(ohci);
+       return ohci_init(ohci);
+}
+
+static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd)
+{
+       int result;
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+       /* Handle root hub init quirk in spider south bridge. */
+       /* Also set PwrOn2PwrGood to 0x7f (254ms). */
+
+       ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM,
+               &ohci->regs->roothub.a);
+       ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b);
+
+       result = ohci_run(ohci);
+
+       if (result < 0) {
+               err("can't start %s", hcd->self.bus_name);
+               ohci_stop(hcd);
+       }
+
+       return result;
+}
+
+static const struct hc_driver ps3_ohci_hc_driver = {
+       .description            = hcd_name,
+       .product_desc           = "PS3 OHCI Host Controller",
+       .hcd_priv_size          = sizeof(struct ohci_hcd),
+       .irq                    = ohci_irq,
+       .flags                  = HCD_MEMORY | HCD_USB11,
+       .reset                  = ps3_ohci_hc_reset,
+       .start                  = ps3_ohci_hc_start,
+       .stop                   = ohci_stop,
+       .shutdown               = ohci_shutdown,
+       .urb_enqueue            = ohci_urb_enqueue,
+       .urb_dequeue            = ohci_urb_dequeue,
+       .endpoint_disable       = ohci_endpoint_disable,
+       .get_frame_number       = ohci_get_frame,
+       .hub_status_data        = ohci_hub_status_data,
+       .hub_control            = ohci_hub_control,
+       .hub_irq_enable         = ohci_rhsc_enable,
+       .start_port_reset       = ohci_start_port_reset,
+#if defined(CONFIG_PM)
+       .bus_suspend            = ohci_bus_suspend,
+       .bus_resume             = ohci_bus_resume,
+#endif
+};
+
+/* redefine dev_dbg to do a syntax check */
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+       const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+{
+       int result;
+       struct usb_hcd *hcd;
+       unsigned int virq;
+       static u64 dummy_mask = DMA_32BIT_MASK;
+
+       if (usb_disabled()) {
+               result = -ENODEV;
+               goto fail_start;
+       }
+
+       result = ps3_mmio_region_create(dev->m_region);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+                       __func__, __LINE__);
+               result = -EPERM;
+               goto fail_mmio;
+       }
+
+       dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+               __LINE__, dev->m_region->lpar_addr);
+
+       result = ps3_alloc_io_irq(dev->interrupt_id, &virq);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+                       __func__, __LINE__, virq);
+               result = -EPERM;
+               goto fail_irq;
+       }
+
+       dev->core.power.power_state = PMSG_ON;
+       dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+       hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id);
+
+       if (!hcd) {
+               dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+                       __LINE__);
+               result = -ENOMEM;
+               goto fail_create_hcd;
+       }
+
+       hcd->rsrc_start = dev->m_region->lpar_addr;
+       hcd->rsrc_len = dev->m_region->len;
+       hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+       if (!hcd->regs) {
+               dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+                       __LINE__);
+               result = -EPERM;
+               goto fail_ioremap;
+       }
+
+       dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+               (unsigned long)hcd->rsrc_start);
+       dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len   %lxh\n", __func__, __LINE__,
+               (unsigned long)hcd->rsrc_len);
+       dev_dbg(&dev->core, "%s:%d: hcd->regs       %lxh\n", __func__, __LINE__,
+               (unsigned long)hcd->regs);
+       dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
+               (unsigned long)virq);
+
+       ps3_system_bus_set_driver_data(dev, hcd);
+
+       result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+       if (result) {
+               dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+                       __func__, __LINE__, result);
+               goto fail_add_hcd;
+       }
+
+       return result;
+
+fail_add_hcd:
+       iounmap(hcd->regs);
+fail_ioremap:
+       usb_put_hcd(hcd);
+fail_create_hcd:
+       ps3_free_io_irq(virq);
+fail_irq:
+       ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+       return result;
+}
+
+static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
+{
+       struct usb_hcd *hcd =
+               (struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+       usb_put_hcd(hcd);
+       ps3_system_bus_set_driver_data(dev, NULL);
+
+       return 0;
+}
+
+MODULE_ALIAS("ps3-ohci");
+
+static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
+       .match_id = PS3_MATCH_ID_OHCI,
+       .core = {
+               .name = "ps3-ohci-driver",
+       },
+       .probe = ps3_ohci_sb_probe,
+       .remove = ps3_ohci_sb_remove,
+};
index 3bbea84..f1563dc 100644 (file)
@@ -369,19 +369,3 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {
        },
 };
 
-static int __init ohci_hcd_pxa27x_init (void)
-{
-       pr_debug (DRIVER_INFO " (pxa27x)");
-       pr_debug ("block sizes: ed %d td %d\n",
-               sizeof (struct ed), sizeof (struct td));
-
-       return platform_driver_register(&ohci_hcd_pxa27x_driver);
-}
-
-static void __exit ohci_hcd_pxa27x_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_pxa27x_driver);
-}
-
-module_init (ohci_hcd_pxa27x_init);
-module_exit (ohci_hcd_pxa27x_cleanup);
index b350d45..6829814 100644 (file)
@@ -501,15 +501,3 @@ static struct platform_driver ohci_hcd_s3c2410_driver = {
        },
 };
 
-static int __init ohci_hcd_s3c2410_init (void)
-{
-       return platform_driver_register(&ohci_hcd_s3c2410_driver);
-}
-
-static void __exit ohci_hcd_s3c2410_cleanup (void)
-{
-       platform_driver_unregister(&ohci_hcd_s3c2410_driver);
-}
-
-module_init (ohci_hcd_s3c2410_init);
-module_exit (ohci_hcd_s3c2410_cleanup);
index fe0090e..0f48f2d 100644 (file)
@@ -269,19 +269,3 @@ static struct sa1111_driver ohci_hcd_sa1111_driver = {
        .remove         = ohci_hcd_sa1111_drv_remove,
 };
 
-static int __init ohci_hcd_sa1111_init (void)
-{
-       dbg (DRIVER_INFO " (SA-1111)");
-       dbg ("block sizes: ed %d td %d",
-               sizeof (struct ed), sizeof (struct td));
-
-       return sa1111_driver_register(&ohci_hcd_sa1111_driver);
-}
-
-static void __exit ohci_hcd_sa1111_cleanup (void)
-{
-       sa1111_driver_unregister(&ohci_hcd_sa1111_driver);
-}
-
-module_init (ohci_hcd_sa1111_init);
-module_exit (ohci_hcd_sa1111_cleanup);
index 405257f..0dafcda 100644 (file)
@@ -394,8 +394,9 @@ struct ohci_hcd {
 #define        OHCI_QUIRK_AMD756       0x01                    /* erratum #4 */
 #define        OHCI_QUIRK_SUPERIO      0x02                    /* natsemi */
 #define        OHCI_QUIRK_INITRESET    0x04                    /* SiS, OPTi, ... */
-#define        OHCI_BIG_ENDIAN         0x08                    /* big endian HC */
-#define        OHCI_QUIRK_ZFMICRO      0x10                    /* Compaq ZFMicro chipset*/
+#define        OHCI_QUIRK_BE_DESC      0x08                    /* BE descriptors */
+#define        OHCI_QUIRK_BE_MMIO      0x10                    /* BE registers */
+#define        OHCI_QUIRK_ZFMICRO      0x20                    /* Compaq ZFMicro chipset*/
        // there are also chip quirks/bugs in init logic
 
 };
@@ -439,117 +440,164 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci)
  * a minority (notably the IBM STB04XXX and the Motorola MPC5200
  * processors) implement them in big endian format.
  *
+ * In addition some more exotic implementations like the Toshiba
+ * Spider (aka SCC) cell southbridge are "mixed" endian, that is,
+ * they have a different endianness for registers vs. in-memory
+ * descriptors.
+ *
  * This attempts to support either format at compile time without a
  * runtime penalty, or both formats with the additional overhead
  * of checking a flag bit.
+ *
+ * That leads to some tricky Kconfig rules howevber. There are
+ * different defaults based on some arch/ppc platforms, though
+ * the basic rules are:
+ *
+ * Controller type              Kconfig options needed
+ * ---------------              ----------------------
+ * little endian                CONFIG_USB_OHCI_LITTLE_ENDIAN
+ *
+ * fully big endian             CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_
+ *                              CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ *
+ * mixed endian                 CONFIG_USB_OHCI_LITTLE_ENDIAN _and_
+ *                              CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC}
+ *
+ * (If you have a mixed endian controller, you -must- also define
+ * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building
+ * both your mixed endian and a fully big endian controller support in
+ * the same kernel image).
  */
 
-#ifdef CONFIG_USB_OHCI_BIG_ENDIAN
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
+#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
+#define big_endian_desc(ohci)  (ohci->flags & OHCI_QUIRK_BE_DESC)
+#else
+#define big_endian_desc(ohci)  1               /* only big endian */
+#endif
+#else
+#define big_endian_desc(ohci)  0               /* only little endian */
+#endif
 
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
 #ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
-#define big_endian(ohci)       (ohci->flags & OHCI_BIG_ENDIAN) /* either */
+#define big_endian_mmio(ohci)  (ohci->flags & OHCI_QUIRK_BE_MMIO)
 #else
-#define big_endian(ohci)       1               /* only big endian */
+#define big_endian_mmio(ohci)  1               /* only big endian */
+#endif
+#else
+#define big_endian_mmio(ohci)  0               /* only little endian */
 #endif
 
 /*
  * Big-endian read/write functions are arch-specific.
  * Other arches can be added if/when they're needed.
+ *
+ * REVISIT: arch/powerpc now has readl/writel_be, so the
+ * definition below can die once the STB04xxx support is
+ * finally ported over.
  */
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
 #define readl_be(addr)         in_be32((__force unsigned *)addr)
 #define writel_be(val, addr)   out_be32((__force unsigned *)addr, val)
 #endif
 
-static inline unsigned int ohci_readl (const struct ohci_hcd *ohci,
-                                                       __hc32 __iomem * regs)
+static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
+                                       __hc32 __iomem * regs)
 {
-       return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+       return big_endian_mmio(ohci) ?
+               readl_be ((__force u32 *)regs) :
+               readl ((__force u32 *)regs);
+#else
+       return readl ((__force u32 *)regs);
+#endif
 }
 
-static inline void ohci_writel (const struct ohci_hcd *ohci,
-                               const unsigned int val, __hc32 __iomem *regs)
+static inline void _ohci_writel (const struct ohci_hcd *ohci,
+                                const unsigned int val, __hc32 __iomem *regs)
 {
-       big_endian(ohci) ? writel_be (val, regs) :
-                          writel (val, (__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+       big_endian_mmio(ohci) ?
+               writel_be (val, (__force u32 *)regs) :
+               writel (val, (__force u32 *)regs);
+#else
+               writel (val, (__force u32 *)regs);
+#endif
 }
 
-#else  /* !CONFIG_USB_OHCI_BIG_ENDIAN */
-
-#define big_endian(ohci)       0               /* only little endian */
-
 #ifdef CONFIG_ARCH_LH7A404
-       /* Marc Singer: at the time this code was written, the LH7A404
-        * had a problem reading the USB host registers.  This
-        * implementation of the ohci_readl function performs the read
-        * twice as a work-around.
-        */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs)
-{
-       *(volatile __force unsigned int*) regs;
-       return *(volatile __force unsigned int*) regs;
-}
+/* Marc Singer: at the time this code was written, the LH7A404
+ * had a problem reading the USB host registers.  This
+ * implementation of the ohci_readl function performs the read
+ * twice as a work-around.
+ */
+#define ohci_readl(o,r)                (_ohci_readl(o,r),_ohci_readl(o,r))
+#define ohci_writel(o,v,r)     _ohci_writel(o,v,r)
 #else
-       /* Standard version of ohci_readl uses standard, platform
-        * specific implementation. */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs)
-{
-       return readl(regs);
-}
+#define ohci_readl(o,r)                _ohci_readl(o,r)
+#define ohci_writel(o,v,r)     _ohci_writel(o,v,r)
 #endif
 
-static inline void ohci_writel (const struct ohci_hcd *ohci,
-                               const unsigned int val, __hc32 __iomem *regs)
-{
-       writel (val, regs);
-}
-
-#endif /* !CONFIG_USB_OHCI_BIG_ENDIAN */
 
 /*-------------------------------------------------------------------------*/
 
 /* cpu to ohci */
 static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
 {
-       return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x);
+       return big_endian_desc(ohci) ?
+               (__force __hc16)cpu_to_be16(x) :
+               (__force __hc16)cpu_to_le16(x);
 }
 
 static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
 {
-       return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x);
+       return big_endian_desc(ohci) ?
+               cpu_to_be16p(x) :
+               cpu_to_le16p(x);
 }
 
 static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
 {
-       return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x);
+       return big_endian_desc(ohci) ?
+               (__force __hc32)cpu_to_be32(x) :
+               (__force __hc32)cpu_to_le32(x);
 }
 
 static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
 {
-       return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x);
+       return big_endian_desc(ohci) ?
+               cpu_to_be32p(x) :
+               cpu_to_le32p(x);
 }
 
 /* ohci to cpu */
 static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
 {
-       return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x);
+       return big_endian_desc(ohci) ?
+               be16_to_cpu((__force __be16)x) :
+               le16_to_cpu((__force __le16)x);
 }
 
 static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
 {
-       return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x);
+       return big_endian_desc(ohci) ?
+               be16_to_cpup((__force __be16 *)x) :
+               le16_to_cpup((__force __le16 *)x);
 }
 
 static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
 {
-       return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x);
+       return big_endian_desc(ohci) ?
+               be32_to_cpu((__force __be32)x) :
+               le32_to_cpu((__force __le32)x);
 }
 
 static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 {
-       return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x);
+       return big_endian_desc(ohci) ?
+               be32_to_cpup((__force __be32 *)x) :
+               le32_to_cpup((__force __le32 *)x);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -557,6 +605,9 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
  * hardware handles 16 bit reads.  That creates a different confusion on
  * some big-endian SOC implementations.  Same thing happens with PSW access.
+ *
+ * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
+ * to arch/powerpc
  */
 
 #ifdef CONFIG_STB03xxx
@@ -568,7 +619,7 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
 {
        u32 tmp;
-       if (big_endian(ohci)) {
+       if (big_endian_desc(ohci)) {
                tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
                tmp >>= OHCI_BE_FRAME_NO_SHIFT;
        } else
@@ -580,7 +631,7 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
 static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
                                  const struct td *td, int index)
 {
-       return (__hc16 *)(big_endian(ohci) ?
+       return (__hc16 *)(big_endian_desc(ohci) ?
                        &td->hwPSW[index ^ 1] : &td->hwPSW[index]);
 }
 
index e345f15..5d6c06b 100644 (file)
@@ -168,9 +168,13 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
                        space, "", qh, qtype,
                        le32_to_cpu(qh->link), le32_to_cpu(element));
        if (qh->type == USB_ENDPOINT_XFER_ISOC)
-               out += sprintf(out, "%*s    period %d frame %x desc [%p]\n",
-                               space, "", qh->period, qh->iso_frame,
-                               qh->iso_packet_desc);
+               out += sprintf(out, "%*s    period %d phase %d load %d us, "
+                               "frame %x desc [%p]\n",
+                               space, "", qh->period, qh->phase, qh->load,
+                               qh->iso_frame, qh->iso_packet_desc);
+       else if (qh->type == USB_ENDPOINT_XFER_INT)
+               out += sprintf(out, "%*s    period %d phase %d load %d us\n",
+                               space, "", qh->period, qh->phase, qh->load);
 
        if (element & UHCI_PTR_QH)
                out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
@@ -208,7 +212,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
                                        space, "", nurbs);
        }
 
-       if (qh->udev) {
+       if (qh->dummy_td) {
                out += sprintf(out, "%*s  Dummy TD\n", space, "");
                out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
        }
@@ -347,31 +351,80 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
        struct uhci_qh *qh;
        struct uhci_td *td;
        struct list_head *tmp, *head;
+       int nframes, nerrs;
 
        out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
        out += sprintf(out, "HC status\n");
        out += uhci_show_status(uhci, out, len - (out - buf));
+
+       out += sprintf(out, "Periodic load table\n");
+       for (i = 0; i < MAX_PHASE; ++i) {
+               out += sprintf(out, "\t%d", uhci->load[i]);
+               if (i % 8 == 7)
+                       *out++ = '\n';
+       }
+       out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n",
+                       uhci->total_load,
+                       uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
+                       uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
        if (debug <= 1)
                return out - buf;
 
        out += sprintf(out, "Frame List\n");
+       nframes = 10;
+       nerrs = 0;
        for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+               __le32 link, qh_dma;
+
+               j = 0;
                td = uhci->frame_cpu[i];
+               link = uhci->frame[i];
                if (!td)
-                       continue;
+                       goto check_link;
 
-               out += sprintf(out, "- Frame %d\n", i); \
-               if (td->dma_handle != (dma_addr_t)uhci->frame[i])
-                       out += sprintf(out, "    frame list does not match td->dma_handle!\n");
+               if (nframes > 0) {
+                       out += sprintf(out, "- Frame %d -> (%08x)\n",
+                                       i, le32_to_cpu(link));
+                       j = 1;
+               }
 
                head = &td->fl_list;
                tmp = head;
                do {
                        td = list_entry(tmp, struct uhci_td, fl_list);
                        tmp = tmp->next;
-                       out += uhci_show_td(td, out, len - (out - buf), 4);
+                       if (cpu_to_le32(td->dma_handle) != link) {
+                               if (nframes > 0)
+                                       out += sprintf(out, "    link does "
+                                               "not match list entry!\n");
+                               else
+                                       ++nerrs;
+                       }
+                       if (nframes > 0)
+                               out += uhci_show_td(td, out,
+                                               len - (out - buf), 4);
+                       link = td->link;
                } while (tmp != head);
+
+check_link:
+               qh_dma = uhci_frame_skel_link(uhci, i);
+               if (link != qh_dma) {
+                       if (nframes > 0) {
+                               if (!j) {
+                                       out += sprintf(out,
+                                               "- Frame %d -> (%08x)\n",
+                                               i, le32_to_cpu(link));
+                                       j = 1;
+                               }
+                               out += sprintf(out, "   link does not match "
+                                       "QH (%08x)!\n", le32_to_cpu(qh_dma));
+                       } else
+                               ++nerrs;
+               }
+               nframes -= j;
        }
+       if (nerrs > 0)
+               out += sprintf(out, "Skipped %d bad links\n", nerrs);
 
        out += sprintf(out, "Skeleton QHs\n");
 
index e0d4c23..49b9d39 100644 (file)
@@ -92,6 +92,34 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
 static void wakeup_rh(struct uhci_hcd *uhci);
 static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
 
+/*
+ * Calculate the link pointer DMA value for the first Skeleton QH in a frame.
+ */
+static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
+{
+       int skelnum;
+
+       /*
+        * The interrupt queues will be interleaved as evenly as possible.
+        * There's not much to be done about period-1 interrupts; they have
+        * to occur in every frame.  But we can schedule period-2 interrupts
+        * in odd-numbered frames, period-4 interrupts in frames congruent
+        * to 2 (mod 4), and so on.  This way each frame only has two
+        * interrupt QHs, which will help spread out bandwidth utilization.
+        *
+        * ffs (Find First bit Set) does exactly what we need:
+        * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
+        * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
+        * ffs >= 7 => not on any high-period queue, so use
+        *      skel_int1_qh = skelqh[9].
+        * Add in UHCI_NUMFRAMES to insure at least one bit is set.
+        */
+       skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
+       if (skelnum <= 1)
+               skelnum = 9;
+       return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle);
+}
+
 #include "uhci-debug.c"
 #include "uhci-q.c"
 #include "uhci-hub.c"
@@ -631,32 +659,11 @@ static int uhci_start(struct usb_hcd *hcd)
        /*
         * Fill the frame list: make all entries point to the proper
         * interrupt queue.
-        *
-        * The interrupt queues will be interleaved as evenly as possible.
-        * There's not much to be done about period-1 interrupts; they have
-        * to occur in every frame.  But we can schedule period-2 interrupts
-        * in odd-numbered frames, period-4 interrupts in frames congruent
-        * to 2 (mod 4), and so on.  This way each frame only has two
-        * interrupt QHs, which will help spread out bandwidth utilization.
         */
        for (i = 0; i < UHCI_NUMFRAMES; i++) {
-               int irq;
-
-               /*
-                * ffs (Find First bit Set) does exactly what we need:
-                * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
-                * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
-                * ffs >= 7 => not on any high-period queue, so use
-                *      skel_int1_qh = skelqh[9].
-                * Add UHCI_NUMFRAMES to insure at least one bit is set.
-                */
-               irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
-               if (irq <= 1)
-                       irq = 9;
 
                /* Only place we don't use the frame list routines */
-               uhci->frame[i] = UHCI_PTR_QH |
-                               cpu_to_le32(uhci->skelqh[irq]->dma_handle);
+               uhci->frame[i] = uhci_frame_skel_link(uhci, i);
        }
 
        /*
index 108e3de..74469b5 100644 (file)
@@ -83,6 +83,7 @@
 #define UHCI_MAX_SOF_NUMBER    2047    /* in an SOF packet */
 #define CAN_SCHEDULE_FRAMES    1000    /* how far in the future frames
                                         * can be scheduled */
+#define MAX_PHASE              32      /* Periodic scheduling length */
 
 /* When no queues need Full-Speed Bandwidth Reclamation,
  * delay this long before turning FSBR off */
@@ -141,6 +142,8 @@ struct uhci_qh {
        unsigned long advance_jiffies;  /* Time of last queue advance */
        unsigned int unlink_frame;      /* When the QH was unlinked */
        unsigned int period;            /* For Interrupt and Isochronous QHs */
+       short phase;                    /* Between 0 and period-1 */
+       short load;                     /* Periodic time requirement, in us */
        unsigned int iso_frame;         /* Frame # for iso_packet_desc */
        int iso_status;                 /* Status for Isochronous URBs */
 
@@ -153,6 +156,8 @@ struct uhci_qh {
        unsigned int needs_fixup:1;     /* Must fix the TD toggle values */
        unsigned int is_stopped:1;      /* Queue was stopped by error/unlink */
        unsigned int wait_expired:1;    /* QH_WAIT_TIMEOUT has expired */
+       unsigned int bandwidth_reserved:1;      /* Periodic bandwidth has
+                                                * been allocated */
 } __attribute__((aligned(16)));
 
 /*
@@ -414,6 +419,9 @@ struct uhci_hcd {
 
        wait_queue_head_t waitqh;               /* endpoint_disable waiters */
        int num_waiting;                        /* Number of waiters */
+
+       int total_load;                         /* Sum of array values */
+       short load[MAX_PHASE];                  /* Periodic allocations */
 };
 
 /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
index 30b8845..2cbb239 100644 (file)
@@ -248,16 +248,26 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
        INIT_LIST_HEAD(&qh->node);
 
        if (udev) {             /* Normal QH */
-               qh->dummy_td = uhci_alloc_td(uhci);
-               if (!qh->dummy_td) {
-                       dma_pool_free(uhci->qh_pool, qh, dma_handle);
-                       return NULL;
+               qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+               if (qh->type != USB_ENDPOINT_XFER_ISOC) {
+                       qh->dummy_td = uhci_alloc_td(uhci);
+                       if (!qh->dummy_td) {
+                               dma_pool_free(uhci->qh_pool, qh, dma_handle);
+                               return NULL;
+                       }
                }
                qh->state = QH_STATE_IDLE;
                qh->hep = hep;
                qh->udev = udev;
                hep->hcpriv = qh;
-               qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+               if (qh->type == USB_ENDPOINT_XFER_INT ||
+                               qh->type == USB_ENDPOINT_XFER_ISOC)
+                       qh->load = usb_calc_bus_time(udev->speed,
+                                       usb_endpoint_dir_in(&hep->desc),
+                                       qh->type == USB_ENDPOINT_XFER_ISOC,
+                                       le16_to_cpu(hep->desc.wMaxPacketSize))
+                               / 1000 + 1;
 
        } else {                /* Skeleton QH */
                qh->state = QH_STATE_ACTIVE;
@@ -275,7 +285,8 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
        list_del(&qh->node);
        if (qh->udev) {
                qh->hep->hcpriv = NULL;
-               uhci_free_td(uhci, qh->dummy_td);
+               if (qh->dummy_td)
+                       uhci_free_td(uhci, qh->dummy_td);
        }
        dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
@@ -327,7 +338,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
                goto done;
        qh->element = UHCI_PTR_TERM;
 
-       /* Control pipes have to worry about toggles */
+       /* Control pipes don't have to worry about toggles */
        if (qh->type == USB_ENDPOINT_XFER_CONTROL)
                goto done;
 
@@ -493,6 +504,121 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh)
                wake_up_all(&uhci->waitqh);
 }
 
+/*
+ * Find the highest existing bandwidth load for a given phase and period.
+ */
+static int uhci_highest_load(struct uhci_hcd *uhci, int phase, int period)
+{
+       int highest_load = uhci->load[phase];
+
+       for (phase += period; phase < MAX_PHASE; phase += period)
+               highest_load = max_t(int, highest_load, uhci->load[phase]);
+       return highest_load;
+}
+
+/*
+ * Set qh->phase to the optimal phase for a periodic transfer and
+ * check whether the bandwidth requirement is acceptable.
+ */
+static int uhci_check_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+       int minimax_load;
+
+       /* Find the optimal phase (unless it is already set) and get
+        * its load value. */
+       if (qh->phase >= 0)
+               minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+       else {
+               int phase, load;
+               int max_phase = min_t(int, MAX_PHASE, qh->period);
+
+               qh->phase = 0;
+               minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+               for (phase = 1; phase < max_phase; ++phase) {
+                       load = uhci_highest_load(uhci, phase, qh->period);
+                       if (load < minimax_load) {
+                               minimax_load = load;
+                               qh->phase = phase;
+                       }
+               }
+       }
+
+       /* Maximum allowable periodic bandwidth is 90%, or 900 us per frame */
+       if (minimax_load + qh->load > 900) {
+               dev_dbg(uhci_dev(uhci), "bandwidth allocation failed: "
+                               "period %d, phase %d, %d + %d us\n",
+                               qh->period, qh->phase, minimax_load, qh->load);
+               return -ENOSPC;
+       }
+       return 0;
+}
+
+/*
+ * Reserve a periodic QH's bandwidth in the schedule
+ */
+static void uhci_reserve_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+       int i;
+       int load = qh->load;
+       char *p = "??";
+
+       for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+               uhci->load[i] += load;
+               uhci->total_load += load;
+       }
+       uhci_to_hcd(uhci)->self.bandwidth_allocated =
+                       uhci->total_load / MAX_PHASE;
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_INT:
+               ++uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+               p = "INT";
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               ++uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+               p = "ISO";
+               break;
+       }
+       qh->bandwidth_reserved = 1;
+       dev_dbg(uhci_dev(uhci),
+                       "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+                       "reserve", qh->udev->devnum,
+                       qh->hep->desc.bEndpointAddress, p,
+                       qh->period, qh->phase, load);
+}
+
+/*
+ * Release a periodic QH's bandwidth reservation
+ */
+static void uhci_release_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+       int i;
+       int load = qh->load;
+       char *p = "??";
+
+       for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+               uhci->load[i] -= load;
+               uhci->total_load -= load;
+       }
+       uhci_to_hcd(uhci)->self.bandwidth_allocated =
+                       uhci->total_load / MAX_PHASE;
+       switch (qh->type) {
+       case USB_ENDPOINT_XFER_INT:
+               --uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+               p = "INT";
+               break;
+       case USB_ENDPOINT_XFER_ISOC:
+               --uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+               p = "ISO";
+               break;
+       }
+       qh->bandwidth_reserved = 0;
+       dev_dbg(uhci_dev(uhci),
+                       "%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+                       "release", qh->udev->devnum,
+                       qh->hep->desc.bEndpointAddress, p,
+                       qh->period, qh->phase, load);
+}
+
 static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
                struct urb *urb)
 {
@@ -796,7 +922,6 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
        wmb();
        qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
        qh->dummy_td = td;
-       qh->period = urb->interval;
 
        usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
                        usb_pipeout(urb->pipe), toggle);
@@ -827,28 +952,42 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
 static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
                struct uhci_qh *qh)
 {
-       int exponent;
+       int ret;
 
        /* USB 1.1 interrupt transfers only involve one packet per interval.
         * Drivers can submit URBs of any length, but longer ones will need
         * multiple intervals to complete.
         */
 
-       /* Figure out which power-of-two queue to use */
-       for (exponent = 7; exponent >= 0; --exponent) {
-               if ((1 << exponent) <= urb->interval)
-                       break;
-       }
-       if (exponent < 0)
-               return -EINVAL;
-       urb->interval = 1 << exponent;
+       if (!qh->bandwidth_reserved) {
+               int exponent;
 
-       if (qh->period == 0)
+               /* Figure out which power-of-two queue to use */
+               for (exponent = 7; exponent >= 0; --exponent) {
+                       if ((1 << exponent) <= urb->interval)
+                               break;
+               }
+               if (exponent < 0)
+                       return -EINVAL;
+               qh->period = 1 << exponent;
                qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
-       else if (qh->period != urb->interval)
-               return -EINVAL;         /* Can't change the period */
 
-       return uhci_submit_common(uhci, urb, qh);
+               /* For now, interrupt phase is fixed by the layout
+                * of the QH lists. */
+               qh->phase = (qh->period / 2) & (MAX_PHASE - 1);
+               ret = uhci_check_bandwidth(uhci, qh);
+               if (ret)
+                       return ret;
+       } else if (qh->period > urb->interval)
+               return -EINVAL;         /* Can't decrease the period */
+
+       ret = uhci_submit_common(uhci, urb, qh);
+       if (ret == 0) {
+               urb->interval = qh->period;
+               if (!qh->bandwidth_reserved)
+                       uhci_reserve_bandwidth(uhci, qh);
+       }
+       return ret;
 }
 
 /*
@@ -995,15 +1134,32 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
                return -EFBIG;
 
        /* Check the period and figure out the starting frame number */
-       if (qh->period == 0) {
+       if (!qh->bandwidth_reserved) {
+               qh->period = urb->interval;
                if (urb->transfer_flags & URB_ISO_ASAP) {
+                       qh->phase = -1;         /* Find the best phase */
+                       i = uhci_check_bandwidth(uhci, qh);
+                       if (i)
+                               return i;
+
+                       /* Allow a little time to allocate the TDs */
                        uhci_get_current_frame_number(uhci);
-                       urb->start_frame = uhci->frame_number + 10;
+                       frame = uhci->frame_number + 10;
+
+                       /* Move forward to the first frame having the
+                        * correct phase */
+                       urb->start_frame = frame + ((qh->phase - frame) &
+                                       (qh->period - 1));
                } else {
                        i = urb->start_frame - uhci->last_iso_frame;
                        if (i <= 0 || i >= UHCI_NUMFRAMES)
                                return -EINVAL;
+                       qh->phase = urb->start_frame & (qh->period - 1);
+                       i = uhci_check_bandwidth(uhci, qh);
+                       if (i)
+                               return i;
                }
+
        } else if (qh->period != urb->interval) {
                return -EINVAL;         /* Can't change the period */
 
@@ -1049,9 +1205,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
        /* Set the interrupt-on-completion flag on the last packet. */
        td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
 
-       qh->skel = uhci->skel_iso_qh;
-       qh->period = urb->interval;
-
        /* Add the TDs to the frame list */
        frame = urb->start_frame;
        list_for_each_entry(td, &urbp->td_list, list) {
@@ -1065,6 +1218,9 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
                qh->iso_status = 0;
        }
 
+       qh->skel = uhci->skel_iso_qh;
+       if (!qh->bandwidth_reserved)
+               uhci_reserve_bandwidth(uhci, qh);
        return 0;
 }
 
@@ -1119,7 +1275,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
        unsigned long flags;
        struct urb_priv *urbp;
        struct uhci_qh *qh;
-       int bustime;
 
        spin_lock_irqsave(&uhci->lock, flags);
 
@@ -1149,35 +1304,11 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
                ret = uhci_submit_bulk(uhci, urb, qh);
                break;
        case USB_ENDPOINT_XFER_INT:
-               if (list_empty(&qh->queue)) {
-                       bustime = usb_check_bandwidth(urb->dev, urb);
-                       if (bustime < 0)
-                               ret = bustime;
-                       else {
-                               ret = uhci_submit_interrupt(uhci, urb, qh);
-                               if (ret == 0)
-                                       usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-                       }
-               } else {        /* inherit from parent */
-                       struct urb_priv *eurbp;
-
-                       eurbp = list_entry(qh->queue.prev, struct urb_priv,
-                                       node);
-                       urb->bandwidth = eurbp->urb->bandwidth;
-                       ret = uhci_submit_interrupt(uhci, urb, qh);
-               }
+               ret = uhci_submit_interrupt(uhci, urb, qh);
                break;
        case USB_ENDPOINT_XFER_ISOC:
                urb->error_count = 0;
-               bustime = usb_check_bandwidth(urb->dev, urb);
-               if (bustime < 0) {
-                       ret = bustime;
-                       break;
-               }
-
                ret = uhci_submit_isochronous(uhci, urb, qh);
-               if (ret == 0)
-                       usb_claim_bandwidth(urb->dev, urb, bustime, 1);
                break;
        }
        if (ret != 0)
@@ -1274,24 +1405,6 @@ __acquires(uhci->lock)
 
        uhci_free_urb_priv(uhci, urbp);
 
-       switch (qh->type) {
-       case USB_ENDPOINT_XFER_ISOC:
-               /* Release bandwidth for Interrupt or Isoc. transfers */
-               if (urb->bandwidth)
-                       usb_release_bandwidth(urb->dev, urb, 1);
-               break;
-       case USB_ENDPOINT_XFER_INT:
-               /* Release bandwidth for Interrupt or Isoc. transfers */
-               /* Make sure we don't release if we have a queued URB */
-               if (list_empty(&qh->queue) && urb->bandwidth)
-                       usb_release_bandwidth(urb->dev, urb, 0);
-               else
-                       /* bandwidth was passed on to queued URB, */
-                       /* so don't let usb_unlink_urb() release it */
-                       urb->bandwidth = 0;
-               break;
-       }
-
        spin_unlock(&uhci->lock);
        usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
        spin_lock(&uhci->lock);
@@ -1300,9 +1413,8 @@ __acquires(uhci->lock)
         * reserved bandwidth. */
        if (list_empty(&qh->queue)) {
                uhci_unlink_qh(uhci, qh);
-
-               /* Bandwidth stuff not yet implemented */
-               qh->period = 0;
+               if (qh->bandwidth_reserved)
+                       uhci_release_bandwidth(uhci, qh);
        }
 }
 
index 63a84bb..d308afd 100644 (file)
@@ -565,11 +565,15 @@ static void mdc800_usb_disconnect (struct usb_interface *intf)
 
                usb_deregister_dev(intf, &mdc800_class);
 
+               /* must be under lock to make sure no URB
+                  is submitted after usb_kill_urb() */
+               mutex_lock(&mdc800->io_lock);
                mdc800->state=NOT_CONNECTED;
 
                usb_kill_urb(mdc800->irq_urb);
                usb_kill_urb(mdc800->write_urb);
                usb_kill_urb(mdc800->download_urb);
+               mutex_unlock(&mdc800->io_lock);
 
                mdc800->dev = NULL;
                usb_set_intfdata(intf, NULL);
index c7d8875..2e71d3c 100644 (file)
@@ -69,6 +69,14 @@ config LOGITECH_FF
          Note: if you say N here, this device will still be supported, but without
          force feedback.
 
+config PANTHERLORD_FF
+       bool "PantherLord USB/PS2 2in1 Adapter support"
+       depends on HID_FF
+       select INPUT_FF_MEMLESS if USB_HID
+       help
+         Say Y here if you have a PantherLord USB/PS2 2in1 Adapter and want
+         to enable force feedback support for it.
+
 config THRUSTMASTER_FF
        bool "ThrustMaster FireStorm Dual Power 2 support (EXPERIMENTAL)"
        depends on HID_FF && EXPERIMENTAL
@@ -344,3 +352,15 @@ config USB_APPLETOUCH
 
          To compile this driver as a module, choose M here: the
          module will be called appletouch.
+
+config USB_GTCO
+        tristate "GTCO CalComp/InterWrite USB Support"
+        depends on USB && INPUT
+        ---help---
+          Say Y here if you want to use the USB version of the GTCO
+          CalComp/InterWrite Tablet.  Make sure to say Y to "Mouse support"
+          (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+          (CONFIG_INPUT_EVDEV) as well.
+
+          To compile this driver as a module, choose M here: the
+          module will be called gtco.
index 1a24b5b..a9d206c 100644 (file)
@@ -17,6 +17,9 @@ endif
 ifeq ($(CONFIG_LOGITECH_FF),y)
        usbhid-objs     += hid-lgff.o
 endif
+ifeq ($(CONFIG_PANTHERLORD_FF),y)
+       usbhid-objs     += hid-plff.o
+endif
 ifeq ($(CONFIG_THRUSTMASTER_FF),y)
        usbhid-objs     += hid-tmff.o
 endif
@@ -45,6 +48,7 @@ obj-$(CONFIG_USB_ACECAD)      += acecad.o
 obj-$(CONFIG_USB_YEALINK)      += yealink.o
 obj-$(CONFIG_USB_XPAD)         += xpad.o
 obj-$(CONFIG_USB_APPLETOUCH)   += appletouch.o
+obj-$(CONFIG_USB_GTCO)         += gtco.o
 
 ifeq ($(CONFIG_USB_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/usb/input/gtco.c b/drivers/usb/input/gtco.c
new file mode 100644 (file)
index 0000000..203cdc1
--- /dev/null
@@ -0,0 +1,1104 @@
+/*    -*- linux-c -*-
+
+GTCO digitizer USB driver
+
+Use the err(), dbg() and info() macros from usb.h for system logging
+
+TO CHECK:  Is pressure done right on report 5?
+
+Copyright (C) 2006  GTCO CalComp
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of GTCO-CalComp not be used in advertising
+or publicity pertaining to distribution of the software without specific,
+written prior permission. GTCO-CalComp makes no representations about the
+suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+
+GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+GTCO CalComp, Inc.
+7125 Riverwood Drive
+Columbia, MD 21046
+
+Jeremy Roberson jroberson@gtcocalcomp.com
+Scott Hill shill@gtcocalcomp.com
+*/
+
+
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/version.h>
+#include <linux/usb/input.h>
+
+/* Version with a Major number of 2 is for kernel inclusion only. */
+#define  GTCO_VERSION   "2.00.0006"
+
+
+/*   MACROS  */
+
+#define VENDOR_ID_GTCO       0x078C
+#define PID_400               0x400
+#define PID_401               0x401
+#define PID_1000              0x1000
+#define PID_1001              0x1001
+#define PID_1002              0x1002
+
+/* Max size of a single report */
+#define REPORT_MAX_SIZE       10
+
+
+/* Bitmask whether pen is in range */
+#define MASK_INRANGE 0x20
+#define MASK_BUTTON  0x01F
+
+#define  PATHLENGTH     64
+
+/* DATA STRUCTURES */
+
+/* Device table */
+static struct usb_device_id gtco_usbid_table [] = {
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },
+       { USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },
+       { }
+};
+MODULE_DEVICE_TABLE (usb, gtco_usbid_table);
+
+
+/* Structure to hold all of our device specific stuff */
+struct gtco {
+
+       struct input_dev  *inputdevice; /* input device struct pointer  */
+       struct usb_device *usbdev; /* the usb device for this device */
+       struct urb        *urbinfo;      /* urb for incoming reports      */
+       dma_addr_t        buf_dma;  /* dma addr of the data buffer*/
+       unsigned char *   buffer;   /* databuffer for reports */
+
+       char  usbpath[PATHLENGTH];
+       int   openCount;
+
+       /* Information pulled from Report Descriptor */
+       u32  usage;
+       u32  min_X;
+       u32  max_X;
+       u32  min_Y;
+       u32  max_Y;
+       s8   mintilt_X;
+       s8   maxtilt_X;
+       s8   mintilt_Y;
+       s8   maxtilt_Y;
+       u32  maxpressure;
+       u32  minpressure;
+};
+
+
+
+/*   Code for parsing the HID REPORT DESCRIPTOR          */
+
+/* From HID1.11 spec */
+struct hid_descriptor
+{
+       struct usb_descriptor_header header;
+       __le16   bcdHID;
+       u8       bCountryCode;
+       u8       bNumDescriptors;
+       u8       bDescriptorType;
+       __le16   wDescriptorLength;
+} __attribute__ ((packed));
+
+
+#define HID_DESCRIPTOR_SIZE   9
+#define HID_DEVICE_TYPE       33
+#define REPORT_DEVICE_TYPE    34
+
+
+#define PREF_TAG(x)     ((x)>>4)
+#define PREF_TYPE(x)    ((x>>2)&0x03)
+#define PREF_SIZE(x)    ((x)&0x03)
+
+#define TYPE_MAIN       0
+#define TYPE_GLOBAL     1
+#define TYPE_LOCAL      2
+#define TYPE_RESERVED   3
+
+#define TAG_MAIN_INPUT        0x8
+#define TAG_MAIN_OUTPUT       0x9
+#define TAG_MAIN_FEATURE      0xB
+#define TAG_MAIN_COL_START    0xA
+#define TAG_MAIN_COL_END      0xC
+
+#define TAG_GLOB_USAGE        0
+#define TAG_GLOB_LOG_MIN      1
+#define TAG_GLOB_LOG_MAX      2
+#define TAG_GLOB_PHYS_MIN     3
+#define TAG_GLOB_PHYS_MAX     4
+#define TAG_GLOB_UNIT_EXP     5
+#define TAG_GLOB_UNIT         6
+#define TAG_GLOB_REPORT_SZ    7
+#define TAG_GLOB_REPORT_ID    8
+#define TAG_GLOB_REPORT_CNT   9
+#define TAG_GLOB_PUSH         10
+#define TAG_GLOB_POP          11
+
+#define TAG_GLOB_MAX          12
+
+#define DIGITIZER_USAGE_TIP_PRESSURE   0x30
+#define DIGITIZER_USAGE_TILT_X         0x3D
+#define DIGITIZER_USAGE_TILT_Y         0x3E
+
+
+/*
+ *
+ *   This is an abbreviated parser for the HID Report Descriptor.  We
+ *   know what devices we are talking to, so this is by no means meant
+ *   to be generic.  We can make some safe assumptions:
+ *
+ *   - We know there are no LONG tags, all short
+ *   - We know that we have no MAIN Feature and MAIN Output items
+ *   - We know what the IRQ reports are supposed to look like.
+ *
+ *   The main purpose of this is to use the HID report desc to figure
+ *   out the mins and maxs of the fields in the IRQ reports.  The IRQ
+ *   reports for 400/401 change slightly if the max X is bigger than 64K.
+ *
+ */
+static void parse_hid_report_descriptor(struct gtco *device, char * report,
+                                       int length)
+{
+       int   x,i=0;
+
+       /* Tag primitive vars */
+       __u8   prefix;
+       __u8   size;
+       __u8   tag;
+       __u8   type;
+       __u8   data   = 0;
+       __u16  data16 = 0;
+       __u32  data32 = 0;
+
+
+       /* For parsing logic */
+       int   inputnum = 0;
+       __u32 usage = 0;
+
+       /* Global Values, indexed by TAG */
+       __u32 globalval[TAG_GLOB_MAX];
+       __u32 oldval[TAG_GLOB_MAX];
+
+       /* Debug stuff */
+       char  maintype='x';
+       char  globtype[12];
+       int   indent=0;
+       char  indentstr[10]="";
+
+
+
+       dbg("======>>>>>>PARSE<<<<<<======");
+
+       /* Walk  this report and pull out the info we need */
+       while (i<length){
+               prefix=report[i];
+
+               /* Skip over prefix */
+               i++;
+
+               /* Determine data size and save the data in the proper variable */
+               size = PREF_SIZE(prefix);
+               switch(size){
+               case 1:
+                       data = report[i];
+                       break;
+               case 2:
+                       data16 = le16_to_cpu(get_unaligned((__le16*)(&(report[i]))));
+                       break;
+               case 3:
+                       size = 4;
+                       data32 = le32_to_cpu(get_unaligned((__le32*)(&(report[i]))));
+               }
+
+               /* Skip size of data */
+               i+=size;
+
+               /* What we do depends on the tag type */
+               tag  = PREF_TAG(prefix);
+               type = PREF_TYPE(prefix);
+               switch(type){
+               case TYPE_MAIN:
+                       strcpy(globtype,"");
+                       switch(tag){
+
+                       case TAG_MAIN_INPUT:
+                               /*
+                                * The INPUT MAIN tag signifies this is
+                                * information from a report.  We need to
+                                * figure out what it is and store the
+                                * min/max values
+                                */
+
+                               maintype='I';
+                               if (data==2){
+                                       strcpy(globtype,"Variable");
+                               }
+                               if (data==3){
+                                       strcpy(globtype,"Var|Const");
+                               }
+
+                               dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
+                                   globalval[TAG_GLOB_REPORT_ID],inputnum,
+                                   globalval[TAG_GLOB_LOG_MAX],globalval[TAG_GLOB_LOG_MAX],
+                                   globalval[TAG_GLOB_LOG_MIN],globalval[TAG_GLOB_LOG_MIN],
+                                   (globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]));
+
+
+                               /*
+                                 We can assume that the first two input items
+                                 are always the X and Y coordinates.  After
+                                 that, we look for everything else by
+                                 local usage value
+                                */
+                               switch (inputnum){
+                               case 0:  /* X coord */
+                                       dbg("GER: X Usage: 0x%x",usage);
+                                       if (device->max_X == 0){
+                                               device->max_X = globalval[TAG_GLOB_LOG_MAX];
+                                               device->min_X = globalval[TAG_GLOB_LOG_MIN];
+                                       }
+
+                                       break;
+                               case 1:  /* Y coord */
+                                       dbg("GER: Y Usage: 0x%x",usage);
+                                       if (device->max_Y == 0){
+                                               device->max_Y = globalval[TAG_GLOB_LOG_MAX];
+                                               device->min_Y = globalval[TAG_GLOB_LOG_MIN];
+                                       }
+                                       break;
+                               default:
+                                       /* Tilt X */
+                                       if (usage == DIGITIZER_USAGE_TILT_X){
+                                               if (device->maxtilt_X == 0){
+                                                       device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
+                                                       device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
+                                               }
+                                       }
+
+                                       /* Tilt Y */
+                                       if (usage == DIGITIZER_USAGE_TILT_Y){
+                                               if (device->maxtilt_Y == 0){
+                                                       device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
+                                                       device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
+                                               }
+                                       }
+
+
+                                       /* Pressure */
+                                       if (usage == DIGITIZER_USAGE_TIP_PRESSURE){
+                                               if (device->maxpressure == 0){
+                                                       device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
+                                                       device->minpressure = globalval[TAG_GLOB_LOG_MIN];
+                                               }
+                                       }
+
+                                       break;
+                               }
+
+                               inputnum++;
+
+
+                               break;
+                       case TAG_MAIN_OUTPUT:
+                               maintype='O';
+                               break;
+                       case TAG_MAIN_FEATURE:
+                               maintype='F';
+                               break;
+                       case TAG_MAIN_COL_START:
+                               maintype='S';
+
+                               if (data==0){
+                                       dbg("======>>>>>> Physical");
+                                       strcpy(globtype,"Physical");
+                               }else{
+                                       dbg("======>>>>>>");
+                               }
+
+                               /* Indent the debug output */
+                               indent++;
+                               for (x=0;x<indent;x++){
+                                       indentstr[x]='-';
+                               }
+                               indentstr[x]=0;
+
+                               /* Save global tags */
+                               for (x=0;x<TAG_GLOB_MAX;x++){
+                                       oldval[x] = globalval[x];
+                               }
+
+                               break;
+                       case TAG_MAIN_COL_END:
+                               dbg("<<<<<<======");
+                               maintype='E';
+                               indent--;
+                               for (x=0;x<indent;x++){
+                                       indentstr[x]='-';
+                               }
+                               indentstr[x]=0;
+
+                               /* Copy global tags back */
+                               for (x=0;x<TAG_GLOB_MAX;x++){
+                                       globalval[x] = oldval[x];
+                               }
+
+                               break;
+                       }
+
+                       switch (size){
+                       case 1:
+                               dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+                                   indentstr,tag,maintype,size,globtype,data);
+                               break;
+                       case 2:
+                               dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+                                   indentstr,tag,maintype,size,globtype, data16);
+                               break;
+                       case 4:
+                               dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+                                   indentstr,tag,maintype,size,globtype,data32);
+                               break;
+                       }
+                       break;
+               case TYPE_GLOBAL:
+                       switch(tag){
+                       case TAG_GLOB_USAGE:
+                               /*
+                                * First time we hit the global usage tag,
+                                * it should tell us the type of device
+                                */
+                               if (device->usage == 0){
+                                       device->usage = data;
+                               }
+                               strcpy(globtype,"USAGE");
+                               break;
+                       case TAG_GLOB_LOG_MIN   :
+                               strcpy(globtype,"LOG_MIN");
+                               break;
+                       case TAG_GLOB_LOG_MAX   :
+                               strcpy(globtype,"LOG_MAX");
+                               break;
+                       case TAG_GLOB_PHYS_MIN  :
+                               strcpy(globtype,"PHYS_MIN");
+                               break;
+                       case TAG_GLOB_PHYS_MAX  :
+                               strcpy(globtype,"PHYS_MAX");
+                               break;
+                       case TAG_GLOB_UNIT_EXP  :
+                               strcpy(globtype,"EXP");
+                               break;
+                       case TAG_GLOB_UNIT      :
+                               strcpy(globtype,"UNIT");
+                               break;
+                       case TAG_GLOB_REPORT_SZ :
+                               strcpy(globtype,"REPORT_SZ");
+                               break;
+                       case TAG_GLOB_REPORT_ID :
+                               strcpy(globtype,"REPORT_ID");
+                               /* New report, restart numbering */
+                               inputnum=0;
+                               break;
+                       case TAG_GLOB_REPORT_CNT:
+                               strcpy(globtype,"REPORT_CNT");
+                               break;
+                       case TAG_GLOB_PUSH :
+                               strcpy(globtype,"PUSH");
+                               break;
+                       case TAG_GLOB_POP:
+                               strcpy(globtype,"POP");
+                               break;
+                       }
+
+
+                       /* Check to make sure we have a good tag number
+                          so we don't overflow array */
+                       if (tag < TAG_GLOB_MAX){
+                               switch (size){
+                               case 1:
+                                       dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data);
+                                       globalval[tag]=data;
+                                       break;
+                               case 2:
+                                       dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16);
+                                       globalval[tag]=data16;
+                                       break;
+                               case 4:
+                                       dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32);
+                                       globalval[tag]=data32;
+                                       break;
+                               }
+                       }else{
+                               dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
+                                   indentstr,tag,size);
+                       }
+
+
+                       break;
+
+               case TYPE_LOCAL:
+                       switch(tag){
+                       case TAG_GLOB_USAGE:
+                               strcpy(globtype,"USAGE");
+                               /* Always 1 byte */
+                               usage = data;
+                               break;
+                       case TAG_GLOB_LOG_MIN   :
+                               strcpy(globtype,"MIN");
+                               break;
+                       case TAG_GLOB_LOG_MAX   :
+                               strcpy(globtype,"MAX");
+                               break;
+                       default:
+                               strcpy(globtype,"UNKNOWN");
+                       }
+
+                       switch (size){
+                       case 1:
+                               dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+                                   indentstr,tag,globtype,size,data);
+                               break;
+                       case 2:
+                               dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+                                   indentstr,tag,globtype,size,data16);
+                               break;
+                       case 4:
+                               dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+                                   indentstr,tag,globtype,size,data32);
+                               break;
+                       }
+
+                       break;
+               }
+
+       }
+
+}
+
+
+
+/*   INPUT DRIVER Routines                               */
+
+
+/*
+ *    Called when opening the input device.  This will submit the URB to
+ *    the usb system so we start getting reports
+ */
+static int gtco_input_open(struct input_dev *inputdev)
+{
+       struct gtco *device;
+       device = inputdev->private;
+
+       device->urbinfo->dev = device->usbdev;
+       if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) {
+               return -EIO;
+       }
+       return 0;
+}
+
+/**
+    Called when closing the input device.  This will unlink the URB
+*/
+static void gtco_input_close(struct input_dev *inputdev)
+{
+       struct gtco *device = inputdev->private;
+
+       usb_kill_urb(device->urbinfo);
+
+}
+
+
+/*
+ *  Setup input device capabilities.  Tell the input system what this
+ *  device is capable of generating.
+ *
+ *  This information is based on what is read from the HID report and
+ *  placed in the struct gtco structure
+ *
+ */
+static void  gtco_setup_caps(struct input_dev  *inputdev)
+{
+       struct gtco *device = inputdev->private;
+
+
+       /* Which events */
+       inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+
+
+       /* Misc event menu block */
+       inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
+
+
+       /* Absolute values based on HID report info */
+       input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
+                            0, 0);
+       input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y,
+                            0, 0);
+
+       /* Proximity */
+       input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0);
+
+       /* Tilt & pressure */
+       input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X,
+                            device->maxtilt_X, 0, 0);
+       input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y,
+                            device->maxtilt_Y, 0, 0);
+       input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
+                            device->maxpressure, 0, 0);
+
+
+       /* Transducer */
+       input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0);
+
+}
+
+
+
+/*   USB Routines  */
+
+
+/*
+ * URB callback routine.  Called when we get IRQ reports from the
+ *  digitizer.
+ *
+ *  This bridges the USB and input device worlds.  It generates events
+ *  on the input device based on the USB reports.
+ */
+static void gtco_urb_callback(struct urb *urbinfo)
+{
+
+
+       struct gtco     *device = urbinfo->context;
+       struct input_dev  *inputdev;
+       int               rc;
+       u32               val = 0;
+       s8                valsigned = 0;
+       char              le_buffer[2];
+
+       inputdev = device->inputdevice;
+
+
+       /* Was callback OK? */
+       if ((urbinfo->status == -ECONNRESET ) ||
+           (urbinfo->status == -ENOENT ) ||
+           (urbinfo->status == -ESHUTDOWN )){
+
+               /* Shutdown is occurring. Return and don't queue up any more */
+               return;
+       }
+
+       if (urbinfo->status != 0 ) {
+               /* Some unknown error.  Hopefully temporary.  Just go and */
+               /* requeue an URB */
+               goto resubmit;
+       }
+
+       /*
+        * Good URB, now process
+        */
+
+       /* PID dependent when we interpret the report */
+       if ((inputdev->id.product == PID_1000 )||
+           (inputdev->id.product == PID_1001 )||
+           (inputdev->id.product == PID_1002 ))
+       {
+
+               /*
+                * Switch on the report ID
+                * Conveniently, the reports have more information, the higher
+                * the report number.  We can just fall through the case
+                * statements if we start with the highest number report
+                */
+               switch(device->buffer[0]){
+               case 5:
+                       /* Pressure is 9 bits */
+                       val =  ((u16)(device->buffer[8]) << 1);
+                       val |= (u16)(device->buffer[7] >> 7);
+                       input_report_abs(inputdev, ABS_PRESSURE,
+                                        device->buffer[8]);
+
+                       /* Mask out the Y tilt value used for pressure */
+                       device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
+
+
+                       /* Fall thru */
+               case 4:
+                       /* Tilt */
+
+                       /* Sign extend these 7 bit numbers.  */
+                       if (device->buffer[6] & 0x40)
+                               device->buffer[6] |= 0x80;
+
+                       if (device->buffer[7] & 0x40)
+                               device->buffer[7] |= 0x80;
+
+
+                       valsigned = (device->buffer[6]);
+                       input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
+
+                       valsigned = (device->buffer[7]);
+                       input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
+
+                       /* Fall thru */
+
+               case 2:
+               case 3:
+                       /* Convert buttons, only 5 bits possible */
+                       val = (device->buffer[5])&MASK_BUTTON;
+
+                       /* We don't apply any meaning to the bitmask,
+                          just report */
+                       input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+                       /*  Fall thru */
+               case 1:
+
+                       /* All reports have X and Y coords in the same place */
+                       val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1])));
+                       input_report_abs(inputdev, ABS_X, val);
+
+                       val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3])));
+                       input_report_abs(inputdev, ABS_Y, val);
+
+
+                       /* Ditto for proximity bit */
+                       if (device->buffer[5]& MASK_INRANGE){
+                               val = 1;
+                       }else{
+                               val=0;
+                       }
+                       input_report_abs(inputdev, ABS_DISTANCE, val);
+
+
+                       /* Report 1 is an exception to how we handle buttons */
+                       /* Buttons are an index, not a bitmask */
+                       if (device->buffer[0] == 1){
+
+                               /* Convert buttons, 5 bit index */
+                               /* Report value of index set as one,
+                                  the rest as 0 */
+                               val = device->buffer[5]& MASK_BUTTON;
+                               dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
+                                   val,val);
+
+                               /*
+                                * We don't apply any meaning to the button
+                                * index, just report it
+                                */
+                               input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+
+                       }
+
+                       break;
+               case 7:
+                       /* Menu blocks */
+                       input_event(inputdev, EV_MSC, MSC_SCAN,
+                                   device->buffer[1]);
+
+
+                       break;
+
+               }
+
+
+       }
+       /* Other pid class */
+       if ((inputdev->id.product == PID_400 )||
+           (inputdev->id.product == PID_401 ))
+       {
+
+               /* Report 2 */
+               if (device->buffer[0] == 2){
+                       /* Menu blocks */
+                       input_event(inputdev, EV_MSC, MSC_SCAN,
+                                   device->buffer[1]);
+               }
+
+               /*  Report 1 */
+               if (device->buffer[0] == 1){
+                       char buttonbyte;
+
+
+                       /*  IF X max > 64K, we still a bit from the y report */
+                       if (device->max_X > 0x10000){
+
+                               val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1])));
+                               val |= (u32)(((u8)device->buffer[3]&0x1)<< 16);
+
+                               input_report_abs(inputdev, ABS_X, val);
+
+                               le_buffer[0]  = (u8)((u8)(device->buffer[3])>>1);
+                               le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7);
+
+                               le_buffer[1]  = (u8)(device->buffer[4]>>1);
+                               le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7);
+
+                               val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer)));
+
+                               input_report_abs(inputdev, ABS_Y, val);
+
+
+                               /*
+                                * Shift the button byte right by one to
+                                * make it look like the standard report
+                                */
+                               buttonbyte = (device->buffer[5])>>1;
+                       }else{
+
+                               val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1]))));
+                               input_report_abs(inputdev, ABS_X, val);
+
+                               val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3]))));
+                               input_report_abs(inputdev, ABS_Y, val);
+
+                               buttonbyte = device->buffer[5];
+
+                       }
+
+
+                       /* BUTTONS and PROXIMITY */
+                       if (buttonbyte& MASK_INRANGE){
+                               val = 1;
+                       }else{
+                               val=0;
+                       }
+                       input_report_abs(inputdev, ABS_DISTANCE, val);
+
+                       /* Convert buttons, only 4 bits possible */
+                       val = buttonbyte&0x0F;
+#ifdef USE_BUTTONS
+                       for ( i=0;i<5;i++){
+                               input_report_key(inputdev, BTN_DIGI+i,val&(1<<i));
+                       }
+#else
+                       /* We don't apply any meaning to the bitmask, just report */
+                       input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+#endif
+                       /* TRANSDUCER */
+                       input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
+
+               }
+       }
+
+       /* Everybody gets report ID's */
+       input_event(inputdev, EV_MSC, MSC_RAW,  device->buffer[0]);
+
+       /* Sync it up */
+       input_sync(inputdev);
+
+ resubmit:
+       rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
+       if (rc != 0) {
+               err("usb_submit_urb failed rc=0x%x",rc);
+       }
+
+}
+
+/*
+ *  The probe routine.  This is called when the kernel find the matching USB
+ *   vendor/product.  We do the following:
+ *
+ *    - Allocate mem for a local structure to manage the device
+ *    - Request a HID Report Descriptor from the device and parse it to
+ *      find out the device parameters
+ *    - Create an input device and assign it attributes
+ *   - Allocate an URB so the device can talk to us when the input
+ *      queue is open
+ */
+static int gtco_probe(struct usb_interface *usbinterface,
+                     const struct usb_device_id *id)
+{
+
+       struct gtco             *device = NULL;
+       char                    path[PATHLENGTH];
+       struct input_dev        *inputdev;
+       struct hid_descriptor   *hid_desc;
+       char                    *report;
+       int                     result=0, retry;
+       struct usb_endpoint_descriptor *endpoint;
+
+       /* Allocate memory for device structure */
+       device = kzalloc(sizeof(struct gtco), GFP_KERNEL);
+       if (device == NULL) {
+               err("No more memory");
+               return -ENOMEM;
+       }
+
+
+       device->inputdevice = input_allocate_device();
+       if (!device->inputdevice){
+               kfree(device);
+               err("No more memory");
+               return -ENOMEM;
+       }
+
+       /* Get pointer to the input device */
+       inputdev = device->inputdevice;
+
+       /* Save interface information */
+       device->usbdev     = usb_get_dev(interface_to_usbdev(usbinterface));
+
+
+       /* Allocate some data for incoming reports */
+       device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE,
+                                          GFP_KERNEL, &(device->buf_dma));
+       if (!device->buffer){
+               input_free_device(device->inputdevice);
+               kfree(device);
+               err("No more memory");
+               return -ENOMEM;
+       }
+
+       /* Allocate URB for reports */
+       device->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
+       if (!device->urbinfo) {
+               usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+                               device->buffer, device->buf_dma);
+               input_free_device(device->inputdevice);
+               kfree(device);
+               err("No more memory");
+               return -ENOMEM;
+       }
+
+
+       /*
+        * The endpoint is always altsetting 0, we know this since we know
+        * this device only has one interrupt endpoint
+        */
+       endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+       /* Some debug */
+       dbg("gtco # interfaces: %d",usbinterface->num_altsetting);
+       dbg("num endpoints:     %d",usbinterface->cur_altsetting->desc.bNumEndpoints);
+       dbg("interface class:   %d",usbinterface->cur_altsetting->desc.bInterfaceClass);
+       dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType);
+       if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+               dbg("endpoint: we have interrupt endpoint\n");
+
+       dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen);
+
+
+
+       /*
+        * Find the HID descriptor so we can find out the size of the
+        * HID report descriptor
+        */
+       if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
+                                    HID_DEVICE_TYPE,&hid_desc) != 0){
+               err("Can't retrieve exta USB descriptor to get hid report descriptor length");
+               usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+                               device->buffer, device->buf_dma);
+               input_free_device(device->inputdevice);
+               kfree(device);
+               return -EIO;
+       }
+
+       dbg("Extra descriptor success: type:%d  len:%d",
+           hid_desc->bDescriptorType,  hid_desc->wDescriptorLength);
+
+       if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) {
+               usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+                               device->buffer, device->buf_dma);
+
+               input_free_device(device->inputdevice);
+               kfree(device);
+               err("No more memory");
+               return -ENOMEM;
+       }
+
+       /* Couple of tries to get reply */
+       for (retry=0;retry<3;retry++) {
+               result = usb_control_msg(device->usbdev,
+                                        usb_rcvctrlpipe(device->usbdev, 0),
+                                        USB_REQ_GET_DESCRIPTOR,
+                                        USB_RECIP_INTERFACE | USB_DIR_IN,
+                                        (REPORT_DEVICE_TYPE << 8),
+                                        0, /* interface */
+                                        report,
+                                        hid_desc->wDescriptorLength,
+                                        5000); /* 5 secs */
+
+               if (result == hid_desc->wDescriptorLength)
+                       break;
+       }
+
+       /* If we didn't get the report, fail */
+       dbg("usb_control_msg result: :%d", result);
+       if (result != hid_desc->wDescriptorLength){
+               kfree(report);
+               usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+                               device->buffer, device->buf_dma);
+               input_free_device(device->inputdevice);
+               kfree(device);
+               err("Failed to get HID Report Descriptor of size: %d",
+                   hid_desc->wDescriptorLength);
+               return -EIO;
+       }
+
+
+       /* Now we parse the report */
+       parse_hid_report_descriptor(device,report,result);
+
+       /* Now we delete it */
+       kfree(report);
+
+       /* Create a device file node */
+       usb_make_path(device->usbdev, path, PATHLENGTH);
+       sprintf(device->usbpath, "%s/input0", path);
+
+
+       /* Set Input device functions */
+       inputdev->open     = gtco_input_open;
+       inputdev->close    = gtco_input_close;
+
+       /* Set input device information */
+       inputdev->name     = "GTCO_CalComp";
+       inputdev->phys     = device->usbpath;
+       inputdev->private  = device;
+
+
+       /* Now set up all the input device capabilities */
+       gtco_setup_caps(inputdev);
+
+       /* Set input device required ID information */
+       usb_to_input_id(device->usbdev, &device->inputdevice->id);
+       inputdev->cdev.dev = &usbinterface->dev;
+
+       /* Setup the URB, it will be posted later on open of input device */
+       endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+       usb_fill_int_urb(device->urbinfo,
+                        device->usbdev,
+                        usb_rcvintpipe(device->usbdev,
+                                       endpoint->bEndpointAddress),
+                        device->buffer,
+                        REPORT_MAX_SIZE,
+                        gtco_urb_callback,
+                        device,
+                        endpoint->bInterval);
+
+       device->urbinfo->transfer_dma = device->buf_dma;
+       device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+
+       /* Save device pointer in USB interface device */
+       usb_set_intfdata(usbinterface, device);
+
+       /* All done, now register the input device */
+       input_register_device(inputdev);
+
+       info( "gtco driver created usb:  %s\n",  path);
+       return 0;
+
+}
+
+/*
+ *  This function is a standard USB function called when the USB device
+ *  is disconnected.  We will get rid of the URV, de-register the input
+ *  device, and free up allocated memory
+ */
+static void gtco_disconnect(struct usb_interface *interface)
+{
+
+       /* Grab private device ptr */
+       struct gtco    *device = usb_get_intfdata (interface);
+       struct input_dev *inputdev;
+
+       inputdev = device->inputdevice;
+
+       /* Now reverse all the registration stuff */
+       if (device) {
+               input_unregister_device(inputdev);
+               usb_kill_urb(device->urbinfo);
+               usb_free_urb(device->urbinfo);
+               usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+                               device->buffer, device->buf_dma);
+               kfree(device);
+       }
+
+       info("gtco driver disconnected");
+}
+
+
+/*   STANDARD MODULE LOAD ROUTINES  */
+
+static struct usb_driver gtco_driverinfo_table = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
+       .owner      = THIS_MODULE,
+#endif
+       .name       = "gtco",
+       .id_table   = gtco_usbid_table,
+       .probe      = gtco_probe,
+       .disconnect = gtco_disconnect,
+};
+/*
+ *  Register this module with the USB subsystem
+ */
+static int __init gtco_init(void)
+{
+       int rc;
+       rc = usb_register(&gtco_driverinfo_table);
+       if (rc) {
+               err("usb_register() failed rc=0x%x", rc);
+       }
+       printk("GTCO usb driver version: %s",GTCO_VERSION);
+       return rc;
+}
+
+/*
+ *   Deregister this module with the USB subsystem
+ */
+static void __exit gtco_exit(void)
+{
+       usb_deregister(&gtco_driverinfo_table);
+}
+
+module_init (gtco_init);
+module_exit (gtco_exit);
+
+MODULE_LICENSE("GPL");
index c6c9e72..84983d1 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <linux/hid.h>
 #include <linux/hiddev.h>
+#include <linux/hid-debug.h>
 #include "usbhid.h"
 
 /*
@@ -220,23 +221,6 @@ static void hid_irq_in(struct urb *urb)
        }
 }
 
-/*
- * Find a report field with a specified HID usage.
- */
-#if 0
-struct hid_field *hid_find_field_by_usage(struct hid_device *hid, __u32 wanted_usage, int type)
-{
-       struct hid_report *report;
-       int i;
-
-       list_for_each_entry(report, &hid->report_enum[type].report_list, list)
-               for (i = 0; i < report->maxfield; i++)
-                       if (report->field[i]->logical == wanted_usage)
-                               return report->field[i];
-       return NULL;
-}
-#endif  /*  0  */
-
 static int hid_submit_out(struct hid_device *hid)
 {
        struct hid_report *report;
@@ -501,7 +485,7 @@ static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
 {
        int result, retries = 4;
 
-       memset(buf,0,size);     // Make sure we parse really received data
+       memset(buf, 0, size);
 
        do {
                result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
@@ -528,18 +512,6 @@ void usbhid_close(struct hid_device *hid)
                usb_kill_urb(usbhid->urbin);
 }
 
-static int hidinput_open(struct input_dev *dev)
-{
-       struct hid_device *hid = dev->private;
-       return usbhid_open(hid);
-}
-
-static void hidinput_close(struct input_dev *dev)
-{
-       struct hid_device *hid = dev->private;
-       usbhid_close(hid);
-}
-
 #define USB_VENDOR_ID_PANJIT           0x134c
 
 #define USB_VENDOR_ID_TURBOX           0x062a
@@ -770,6 +742,7 @@ void usbhid_init_reports(struct hid_device *hid)
 #define USB_DEVICE_ID_APPLE_GEYSER4_JIS        0x021c
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
+#define USB_DEVICE_ID_APPLE_IR         0x8240
 
 #define USB_VENDOR_ID_CHERRY           0x046a
 #define USB_DEVICE_ID_CHERRY_CYMOTION  0x0023
@@ -792,6 +765,12 @@ void usbhid_init_reports(struct hid_device *hid)
 #define USB_VENDOR_ID_IMATION          0x0718
 #define USB_DEVICE_ID_DISC_STAKKA      0xd000
 
+#define USB_VENDOR_ID_PANTHERLORD      0x0810
+#define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK    0x0001
+
+#define USB_VENDOR_ID_SONY                     0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER      0x0268
+
 /*
  * Alphabetically sorted blacklist by quirk type.
  */
@@ -946,19 +925,21 @@ static const struct hid_blacklist {
 
        { USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION, HID_QUIRK_CYMOTION },
 
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN },
-       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER3_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ANSI, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_ISO, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE | HID_QUIRK_POWERBOOK_ISO_KEYBOARD},
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_JIS, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_POWERBOOK_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
+
+       { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IR, HID_QUIRK_IGNORE },
 
        { USB_VENDOR_ID_PANJIT, 0x0001, HID_QUIRK_IGNORE },
        { USB_VENDOR_ID_PANJIT, 0x0002, HID_QUIRK_IGNORE },
@@ -969,6 +950,10 @@ static const struct hid_blacklist {
 
        { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_USB_RECEIVER, HID_QUIRK_BAD_RELATIVE_KEYS },
 
+       { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
+
+       { USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
+
        { 0, 0 }
 };
 
@@ -1033,6 +1018,32 @@ static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
        }
 }
 
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational".  Without this, the ps3 controller will not report any
+ * events.
+ */
+static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
+{
+       int result;
+       char *buf = kmalloc(18, GFP_KERNEL);
+
+       if (!buf)
+               return;
+
+       result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+                                HID_REQ_GET_REPORT,
+                                USB_DIR_IN | USB_TYPE_CLASS |
+                                USB_RECIP_INTERFACE,
+                                (3 << 8) | 0xf2, ifnum, buf, 17,
+                                USB_CTRL_GET_TIMEOUT);
+
+       if (result < 0)
+               err("%s failed: %d\n", __func__, result);
+
+       kfree(buf);
+}
+
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
        struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1064,6 +1075,11 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
        if (quirks & HID_QUIRK_IGNORE)
                return NULL;
 
+       if ((quirks & HID_QUIRK_IGNORE_MOUSE) &&
+               (interface->desc.bInterfaceProtocol == USB_INTERFACE_PROTOCOL_MOUSE))
+                       return NULL;
+
+
        if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) &&
            (!interface->desc.bNumEndpoints ||
             usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) {
@@ -1235,8 +1251,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
        usbhid->urbctrl->transfer_dma = usbhid->ctrlbuf_dma;
        usbhid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
        hid->hidinput_input_event = usb_hidinput_input_event;
-       hid->hidinput_open = hidinput_open;
-       hid->hidinput_close = hidinput_close;
+       hid->hid_open = usbhid_open;
+       hid->hid_close = usbhid_close;
 #ifdef CONFIG_USB_HIDDEV
        hid->hiddev_hid_event = hiddev_hid_event;
        hid->hiddev_report_event = hiddev_report_event;
@@ -1315,13 +1331,13 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
                return -ENODEV;
        }
 
-       /* This only gets called when we are a single-input (most of the
-        * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is
-        * only useful in this case, and not for multi-input quirks. */
-       if ((hid->claimed & HID_CLAIMED_INPUT) &&
-                       !(hid->quirks & HID_QUIRK_MULTI_INPUT))
+       if ((hid->claimed & HID_CLAIMED_INPUT))
                hid_ff_init(hid);
 
+       if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
+               hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
+                       intf->cur_altsetting->desc.bInterfaceNumber);
+
        printk(KERN_INFO);
 
        if (hid->claimed & HID_CLAIMED_INPUT)
index 59ed65e..5d14505 100644 (file)
@@ -58,6 +58,9 @@ static struct hid_ff_initializer inits[] = {
        { 0x46d, 0xc295, hid_lgff_init }, /* Logitech MOMO force wheel */
        { 0x46d, 0xc219, hid_lgff_init }, /* Logitech Cordless rumble pad 2 */
 #endif
+#ifdef CONFIG_PANTHERLORD_FF
+       { 0x810, 0x0001, hid_plff_init },
+#endif
 #ifdef CONFIG_THRUSTMASTER_FF
        { 0x44f, 0xb304, hid_tmff_init },
 #endif
index e474662..4f4fc3b 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/hid.h>
 #include "usbhid.h"
 
-struct device_type {
+struct dev_type {
        u16 idVendor;
        u16 idProduct;
        const signed short *ff;
@@ -48,7 +48,7 @@ static const signed short ff_joystick[] = {
        -1
 };
 
-static const struct device_type devices[] = {
+static const struct dev_type devices[] = {
        { 0x046d, 0xc211, ff_rumble },
        { 0x046d, 0xc219, ff_rumble },
        { 0x046d, 0xc283, ff_joystick },
diff --git a/drivers/usb/input/hid-plff.c b/drivers/usb/input/hid-plff.c
new file mode 100644 (file)
index 0000000..76d2e6e
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ *  Force feedback support for PantherLord USB/PS2 2in1 Adapter devices
+ *
+ *  Copyright (c) 2007 Anssi Hannula <anssi.hannula@gmail.com>
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+/* #define DEBUG */
+
+#define debug(format, arg...) pr_debug("hid-plff: " format "\n" , ## arg)
+
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include "usbhid.h"
+
+struct plff_device {
+       struct hid_report *report;
+};
+
+static int hid_plff_play(struct input_dev *dev, void *data,
+                        struct ff_effect *effect)
+{
+       struct hid_device *hid = dev->private;
+       struct plff_device *plff = data;
+       int left, right;
+
+       left = effect->u.rumble.strong_magnitude;
+       right = effect->u.rumble.weak_magnitude;
+       debug("called with 0x%04x 0x%04x", left, right);
+
+       left = left * 0x7f / 0xffff;
+       right = right * 0x7f / 0xffff;
+
+       plff->report->field[0]->value[2] = left;
+       plff->report->field[0]->value[3] = right;
+       debug("running with 0x%02x 0x%02x", left, right);
+       usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+
+       return 0;
+}
+
+int hid_plff_init(struct hid_device *hid)
+{
+       struct plff_device *plff;
+       struct hid_report *report;
+       struct hid_input *hidinput;
+       struct list_head *report_list =
+                       &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+       struct list_head *report_ptr = report_list;
+       struct input_dev *dev;
+       int error;
+
+       /* The device contains 2 output reports (one for each
+          HID_QUIRK_MULTI_INPUT device), both containing 1 field, which
+          contains 4 ff00.0002 usages and 4 16bit absolute values.
+
+          The 2 input reports also contain a field which contains
+          8 ff00.0001 usages and 8 boolean values. Their meaning is
+          currently unknown. */
+
+       if (list_empty(report_list)) {
+               printk(KERN_ERR "hid-plff: no output reports found\n");
+               return -ENODEV;
+       }
+
+       list_for_each_entry(hidinput, &hid->inputs, list) {
+
+               report_ptr = report_ptr->next;
+
+               if (report_ptr == report_list) {
+                       printk(KERN_ERR "hid-plff: required output report is missing\n");
+                       return -ENODEV;
+               }
+
+               report = list_entry(report_ptr, struct hid_report, list);
+               if (report->maxfield < 1) {
+                       printk(KERN_ERR "hid-plff: no fields in the report\n");
+                       return -ENODEV;
+               }
+
+               if (report->field[0]->report_count < 4) {
+                       printk(KERN_ERR "hid-plff: not enough values in the field\n");
+                       return -ENODEV;
+               }
+
+               plff = kzalloc(sizeof(struct plff_device), GFP_KERNEL);
+               if (!plff)
+                       return -ENOMEM;
+
+               dev = hidinput->input;
+
+               set_bit(FF_RUMBLE, dev->ffbit);
+
+               error = input_ff_create_memless(dev, plff, hid_plff_play);
+               if (error) {
+                       kfree(plff);
+                       return error;
+               }
+
+               plff->report = report;
+               plff->report->field[0]->value[0] = 0x00;
+               plff->report->field[0]->value[1] = 0x00;
+               plff->report->field[0]->value[2] = 0x00;
+               plff->report->field[0]->value[3] = 0x00;
+               usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
+       }
+
+       printk(KERN_INFO "hid-plff: Force feedback for PantherLord USB/PS2 "
+              "2in1 Adapters by Anssi Hannula <anssi.hannula@gmail.com>\n");
+
+       return 0;
+}
index c941853..15c70bd 100644 (file)
@@ -269,7 +269,7 @@ static int idmouse_release(struct inode *inode, struct file *file)
        /* prevent a race condition with open() */
        mutex_lock(&disconnect_mutex);
 
-       dev = (struct usb_idmouse *) file->private_data;
+       dev = file->private_data;
 
        if (dev == NULL) {
                mutex_unlock(&disconnect_mutex);
@@ -304,17 +304,15 @@ static int idmouse_release(struct inode *inode, struct file *file)
 static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count,
                                loff_t * ppos)
 {
-       struct usb_idmouse *dev;
+       struct usb_idmouse *dev = file->private_data;
        int result;
 
-       dev = (struct usb_idmouse *) file->private_data;
-
        /* lock this object */
-       down (&dev->sem);
+       down(&dev->sem);
 
        /* verify that the device wasn't unplugged */
        if (!dev->present) {
-               up (&dev->sem);
+               up(&dev->sem);
                return -ENODEV;
        }
 
index 384fa37..fdf6847 100644 (file)
@@ -69,7 +69,7 @@ struct rio_usb_data {
         char *obuf, *ibuf;              /* transfer buffers */
         char bulk_in_ep, bulk_out_ep;   /* Endpoint assignments */
         wait_queue_head_t wait_q;       /* for timeouts */
-       struct semaphore lock;          /* general race avoidance */
+       struct mutex lock;          /* general race avoidance */
 };
 
 static struct rio_usb_data rio_instance;
@@ -78,17 +78,17 @@ static int open_rio(struct inode *inode, struct file *file)
 {
        struct rio_usb_data *rio = &rio_instance;
 
-       down(&(rio->lock));
+       mutex_lock(&(rio->lock));
 
        if (rio->isopen || !rio->present) {
-               up(&(rio->lock));
+               mutex_unlock(&(rio->lock));
                return -EBUSY;
        }
        rio->isopen = 1;
 
        init_waitqueue_head(&rio->wait_q);
 
-       up(&(rio->lock));
+       mutex_unlock(&(rio->lock));
 
        info("Rio opened.");
 
@@ -117,7 +117,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
        int retries;
        int retval=0;
 
-       down(&(rio->lock));
+       mutex_lock(&(rio->lock));
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
@@ -257,7 +257,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
 
 
 err_out:
-       up(&(rio->lock));
+       mutex_unlock(&(rio->lock));
        return retval;
 }
 
@@ -275,14 +275,17 @@ write_rio(struct file *file, const char __user *buffer,
        int result = 0;
        int maxretry;
        int errn = 0;
+       int intr;
 
-       down(&(rio->lock));
+       intr = mutex_lock_interruptible(&(rio->lock));
+       if (intr)
+               return -EINTR;
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->rio_dev == NULL )
        {
-               up(&(rio->lock));
+               mutex_unlock(&(rio->lock));
                return -ENODEV;
        }
 
@@ -305,7 +308,7 @@ write_rio(struct file *file, const char __user *buffer,
                                goto error;
                        }
                        if (signal_pending(current)) {
-                               up(&(rio->lock));
+                               mutex_unlock(&(rio->lock));
                                return bytes_written ? bytes_written : -EINTR;
                        }
 
@@ -341,12 +344,12 @@ write_rio(struct file *file, const char __user *buffer,
                buffer += copy_size;
        } while (count > 0);
 
-       up(&(rio->lock));
+       mutex_unlock(&(rio->lock));
 
        return bytes_written ? bytes_written : -EIO;
 
 error:
-       up(&(rio->lock));
+       mutex_unlock(&(rio->lock));
        return errn;
 }
 
@@ -361,14 +364,17 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
        int result;
        int maxretry = 10;
        char *ibuf;
+       int intr;
 
-       down(&(rio->lock));
+       intr = mutex_lock_interruptible(&(rio->lock));
+       if (intr)
+               return -EINTR;
        /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->rio_dev == NULL )
        {
-               up(&(rio->lock));
+               mutex_unlock(&(rio->lock));
                return -ENODEV;
        }
 
@@ -379,11 +385,11 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
 
        while (count > 0) {
                if (signal_pending(current)) {
-                       up(&(rio->lock));
+                       mutex_unlock(&(rio->lock));
                        return read_count ? read_count : -EINTR;
                }
                if (!rio->rio_dev) {
-                       up(&(rio->lock));
+                       mutex_unlock(&(rio->lock));
                        return -ENODEV;
                }
                this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
@@ -400,7 +406,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
                        count = this_read = partial;
                } else if (result == -ETIMEDOUT || result == 15) {      /* FIXME: 15 ??? */
                        if (!maxretry--) {
-                               up(&(rio->lock));
+                               mutex_unlock(&(rio->lock));
                                err("read_rio: maxretry timeout");
                                return -ETIME;
                        }
@@ -409,18 +415,18 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
                        finish_wait(&rio->wait_q, &wait);
                        continue;
                } else if (result != -EREMOTEIO) {
-                       up(&(rio->lock));
+                       mutex_unlock(&(rio->lock));
                        err("Read Whoops - result:%u partial:%u this_read:%u",
                             result, partial, this_read);
                        return -EIO;
                } else {
-                       up(&(rio->lock));
+                       mutex_unlock(&(rio->lock));
                        return (0);
                }
 
                if (this_read) {
                        if (copy_to_user(buffer, ibuf, this_read)) {
-                               up(&(rio->lock));
+                               mutex_unlock(&(rio->lock));
                                return -EFAULT;
                        }
                        count -= this_read;
@@ -428,7 +434,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
                        buffer += this_read;
                }
        }
-       up(&(rio->lock));
+       mutex_unlock(&(rio->lock));
        return read_count;
 }
 
@@ -480,7 +486,7 @@ static int probe_rio(struct usb_interface *intf,
        }
        dbg("probe_rio: ibuf address:%p", rio->ibuf);
 
-       init_MUTEX(&(rio->lock));
+       mutex_init(&(rio->lock));
 
        usb_set_intfdata (intf, rio);
        rio->present = 1;
@@ -496,12 +502,12 @@ static void disconnect_rio(struct usb_interface *intf)
        if (rio) {
                usb_deregister_dev(intf, &usb_rio_class);
 
-               down(&(rio->lock));
+               mutex_lock(&(rio->lock));
                if (rio->isopen) {
                        rio->isopen = 0;
                        /* better let it finish - the release will do whats needed */
                        rio->rio_dev = NULL;
-                       up(&(rio->lock));
+                       mutex_unlock(&(rio->lock));
                        return;
                }
                kfree(rio->ibuf);
@@ -510,7 +516,7 @@ static void disconnect_rio(struct usb_interface *intf)
                info("USB Rio disconnected.");
 
                rio->present = 0;
-               up(&(rio->lock));
+               mutex_unlock(&(rio->lock));
        }
 }
 
index 3cf3ea3..90c5953 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for USB Core files and filesystem
 #
 
-usbmon-objs    := mon_main.o mon_stat.o mon_text.o mon_dma.o
+usbmon-objs    := mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o
 
 # This does not use CONFIG_USB_MON because we want this to use a tristate.
 obj-$(CONFIG_USB)      += usbmon.o
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
new file mode 100644 (file)
index 0000000..c01dfe6
--- /dev/null
@@ -0,0 +1,1172 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * This is a binary format reader.
+ *
+ * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it)
+ * Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+#include <linux/compat.h>
+#include <linux/mm.h>
+
+#include <asm/uaccess.h>
+
+#include "usb_mon.h"
+
+/*
+ * Defined by USB 2.0 clause 9.3, table 9.2.
+ */
+#define SETUP_LEN  8
+
+/* ioctl macros */
+#define MON_IOC_MAGIC 0x92
+
+#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1)
+/* #2 used to be MON_IOCX_URB, removed before it got into Linus tree */
+#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4)
+#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5)
+#define MON_IOCX_GET   _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get)
+#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch)
+#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8)
+#ifdef CONFIG_COMPAT
+#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32)
+#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32)
+#endif
+
+/*
+ * Some architectures have enormous basic pages (16KB for ia64, 64KB for ppc).
+ * But it's all right. Just use a simple way to make sure the chunk is never
+ * smaller than a page.
+ *
+ * N.B. An application does not know our chunk size.
+ *
+ * Woops, get_zeroed_page() returns a single page. I guess we're stuck with
+ * page-sized chunks for the time being.
+ */
+#define CHUNK_SIZE   PAGE_SIZE
+#define CHUNK_ALIGN(x)   (((x)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1))
+
+/*
+ * The magic limit was calculated so that it allows the monitoring
+ * application to pick data once in two ticks. This way, another application,
+ * which presumably drives the bus, gets to hog CPU, yet we collect our data.
+ * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an
+ * enormous overhead built into the bus protocol, so we need about 1000 KB.
+ *
+ * This is still too much for most cases, where we just snoop a few
+ * descriptor fetches for enumeration. So, the default is a "reasonable"
+ * amount for systems with HZ=250 and incomplete bus saturation.
+ *
+ * XXX What about multi-megabyte URBs which take minutes to transfer?
+ */
+#define BUFF_MAX  CHUNK_ALIGN(1200*1024)
+#define BUFF_DFL   CHUNK_ALIGN(300*1024)
+#define BUFF_MIN     CHUNK_ALIGN(8*1024)
+
+/*
+ * The per-event API header (2 per URB).
+ *
+ * This structure is seen in userland as defined by the documentation.
+ */
+struct mon_bin_hdr {
+       u64 id;                 /* URB ID - from submission to callback */
+       unsigned char type;     /* Same as in text API; extensible. */
+       unsigned char xfer_type;        /* ISO, Intr, Control, Bulk */
+       unsigned char epnum;    /* Endpoint number and transfer direction */
+       unsigned char devnum;   /* Device address */
+       unsigned short busnum;  /* Bus number */
+       char flag_setup;
+       char flag_data;
+       s64 ts_sec;             /* gettimeofday */
+       s32 ts_usec;            /* gettimeofday */
+       int status;
+       unsigned int len_urb;   /* Length of data (submitted or actual) */
+       unsigned int len_cap;   /* Delivered length */
+       unsigned char setup[SETUP_LEN]; /* Only for Control S-type */
+};
+
+/* per file statistic */
+struct mon_bin_stats {
+       u32 queued;
+       u32 dropped;
+};
+
+struct mon_bin_get {
+       struct mon_bin_hdr __user *hdr; /* Only 48 bytes, not 64. */
+       void __user *data;
+       size_t alloc;           /* Length of data (can be zero) */
+};
+
+struct mon_bin_mfetch {
+       u32 __user *offvec;     /* Vector of events fetched */
+       u32 nfetch;             /* Number of events to fetch (out: fetched) */
+       u32 nflush;             /* Number of events to flush */
+};
+
+#ifdef CONFIG_COMPAT
+struct mon_bin_get32 {
+       u32 hdr32;
+       u32 data32;
+       u32 alloc32;
+};
+
+struct mon_bin_mfetch32 {
+        u32 offvec32;
+        u32 nfetch32;
+        u32 nflush32;
+};
+#endif
+
+/* Having these two values same prevents wrapping of the mon_bin_hdr */
+#define PKT_ALIGN   64
+#define PKT_SIZE    64
+
+/* max number of USB bus supported */
+#define MON_BIN_MAX_MINOR 128
+
+/*
+ * The buffer: map of used pages.
+ */
+struct mon_pgmap {
+       struct page *pg;
+       unsigned char *ptr;     /* XXX just use page_to_virt everywhere? */
+};
+
+/*
+ * This gets associated with an open file struct.
+ */
+struct mon_reader_bin {
+       /* The buffer: one per open. */
+       spinlock_t b_lock;              /* Protect b_cnt, b_in */
+       unsigned int b_size;            /* Current size of the buffer - bytes */
+       unsigned int b_cnt;             /* Bytes used */
+       unsigned int b_in, b_out;       /* Offsets into buffer - bytes */
+       unsigned int b_read;            /* Amount of read data in curr. pkt. */
+       struct mon_pgmap *b_vec;        /* The map array */
+       wait_queue_head_t b_wait;       /* Wait for data here */
+
+       struct mutex fetch_lock;        /* Protect b_read, b_out */
+       int mmap_active;
+
+       /* A list of these is needed for "bus 0". Some time later. */
+       struct mon_reader r;
+
+       /* Stats */
+       unsigned int cnt_lost;
+};
+
+static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
+    unsigned int offset)
+{
+       return (struct mon_bin_hdr *)
+           (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE);
+}
+
+#define MON_RING_EMPTY(rp)     ((rp)->b_cnt == 0)
+
+static dev_t mon_bin_dev0;
+static struct cdev mon_bin_cdev;
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+    unsigned int offset, unsigned int size);
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp);
+static int mon_alloc_buff(struct mon_pgmap *map, int npages);
+static void mon_free_buff(struct mon_pgmap *map, int npages);
+
+/*
+ * This is a "chunked memcpy". It does not manipulate any counters.
+ * But it returns the new offset for repeated application.
+ */
+unsigned int mon_copy_to_buff(const struct mon_reader_bin *this,
+    unsigned int off, const unsigned char *from, unsigned int length)
+{
+       unsigned int step_len;
+       unsigned char *buf;
+       unsigned int in_page;
+
+       while (length) {
+               /*
+                * Determine step_len.
+                */
+               step_len = length;
+               in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+               if (in_page < step_len)
+                       step_len = in_page;
+
+               /*
+                * Copy data and advance pointers.
+                */
+               buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+               memcpy(buf, from, step_len);
+               if ((off += step_len) >= this->b_size) off = 0;
+               from += step_len;
+               length -= step_len;
+       }
+       return off;
+}
+
+/*
+ * This is a little worse than the above because it's "chunked copy_to_user".
+ * The return value is an error code, not an offset.
+ */
+static int copy_from_buf(const struct mon_reader_bin *this, unsigned int off,
+    char __user *to, int length)
+{
+       unsigned int step_len;
+       unsigned char *buf;
+       unsigned int in_page;
+
+       while (length) {
+               /*
+                * Determine step_len.
+                */
+               step_len = length;
+               in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+               if (in_page < step_len)
+                       step_len = in_page;
+
+               /*
+                * Copy data and advance pointers.
+                */
+               buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+               if (copy_to_user(to, buf, step_len))
+                       return -EINVAL;
+               if ((off += step_len) >= this->b_size) off = 0;
+               to += step_len;
+               length -= step_len;
+       }
+       return 0;
+}
+
+/*
+ * Allocate an (aligned) area in the buffer.
+ * This is called under b_lock.
+ * Returns ~0 on failure.
+ */
+static unsigned int mon_buff_area_alloc(struct mon_reader_bin *rp,
+    unsigned int size)
+{
+       unsigned int offset;
+
+       size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+       if (rp->b_cnt + size > rp->b_size)
+               return ~0;
+       offset = rp->b_in;
+       rp->b_cnt += size;
+       if ((rp->b_in += size) >= rp->b_size)
+               rp->b_in -= rp->b_size;
+       return offset;
+}
+
+/*
+ * This is the same thing as mon_buff_area_alloc, only it does not allow
+ * buffers to wrap. This is needed by applications which pass references
+ * into mmap-ed buffers up their stacks (libpcap can do that).
+ *
+ * Currently, we always have the header stuck with the data, although
+ * it is not strictly speaking necessary.
+ *
+ * When a buffer would wrap, we place a filler packet to mark the space.
+ */
+static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp,
+    unsigned int size)
+{
+       unsigned int offset;
+       unsigned int fill_size;
+
+       size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+       if (rp->b_cnt + size > rp->b_size)
+               return ~0;
+       if (rp->b_in + size > rp->b_size) {
+               /*
+                * This would wrap. Find if we still have space after
+                * skipping to the end of the buffer. If we do, place
+                * a filler packet and allocate a new packet.
+                */
+               fill_size = rp->b_size - rp->b_in;
+               if (rp->b_cnt + size + fill_size > rp->b_size)
+                       return ~0;
+               mon_buff_area_fill(rp, rp->b_in, fill_size);
+
+               offset = 0;
+               rp->b_in = size;
+               rp->b_cnt += size + fill_size;
+       } else if (rp->b_in + size == rp->b_size) {
+               offset = rp->b_in;
+               rp->b_in = 0;
+               rp->b_cnt += size;
+       } else {
+               offset = rp->b_in;
+               rp->b_in += size;
+               rp->b_cnt += size;
+       }
+       return offset;
+}
+
+/*
+ * Return a few (kilo-)bytes to the head of the buffer.
+ * This is used if a DMA fetch fails.
+ */
+static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size)
+{
+
+       size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+       rp->b_cnt -= size;
+       if (rp->b_in < size)
+               rp->b_in += rp->b_size;
+       rp->b_in -= size;
+}
+
+/*
+ * This has to be called under both b_lock and fetch_lock, because
+ * it accesses both b_cnt and b_out.
+ */
+static void mon_buff_area_free(struct mon_reader_bin *rp, unsigned int size)
+{
+
+       size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+       rp->b_cnt -= size;
+       if ((rp->b_out += size) >= rp->b_size)
+               rp->b_out -= rp->b_size;
+}
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+    unsigned int offset, unsigned int size)
+{
+       struct mon_bin_hdr *ep;
+
+       ep = MON_OFF2HDR(rp, offset);
+       memset(ep, 0, PKT_SIZE);
+       ep->type = '@';
+       ep->len_cap = size - PKT_SIZE;
+}
+
+static inline char mon_bin_get_setup(unsigned char *setupb,
+    const struct urb *urb, char ev_type)
+{
+
+       if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+               return '-';
+
+       if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+               return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
+       if (urb->setup_packet == NULL)
+               return 'Z';
+
+       memcpy(setupb, urb->setup_packet, SETUP_LEN);
+       return 0;
+}
+
+static char mon_bin_get_data(const struct mon_reader_bin *rp,
+    unsigned int offset, struct urb *urb, unsigned int length)
+{
+
+       if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) {
+               mon_dmapeek_vec(rp, offset, urb->transfer_dma, length);
+               return 0;
+       }
+
+       if (urb->transfer_buffer == NULL)
+               return 'Z';
+
+       mon_copy_to_buff(rp, offset, urb->transfer_buffer, length);
+       return 0;
+}
+
+static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
+    char ev_type)
+{
+       unsigned long flags;
+       struct timeval ts;
+       unsigned int urb_length;
+       unsigned int offset;
+       unsigned int length;
+       struct mon_bin_hdr *ep;
+       char data_tag = 0;
+
+       do_gettimeofday(&ts);
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+
+       /*
+        * Find the maximum allowable length, then allocate space.
+        */
+       urb_length = (ev_type == 'S') ?
+           urb->transfer_buffer_length : urb->actual_length;
+       length = urb_length;
+
+       if (length >= rp->b_size/5)
+               length = rp->b_size/5;
+
+       if (usb_pipein(urb->pipe)) {
+               if (ev_type == 'S') {
+                       length = 0;
+                       data_tag = '<';
+               }
+       } else {
+               if (ev_type == 'C') {
+                       length = 0;
+                       data_tag = '>';
+               }
+       }
+
+       if (rp->mmap_active)
+               offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE);
+       else
+               offset = mon_buff_area_alloc(rp, length + PKT_SIZE);
+       if (offset == ~0) {
+               rp->cnt_lost++;
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+               return;
+       }
+
+       ep = MON_OFF2HDR(rp, offset);
+       if ((offset += PKT_SIZE) >= rp->b_size) offset = 0;
+
+       /*
+        * Fill the allocated area.
+        */
+       memset(ep, 0, PKT_SIZE);
+       ep->type = ev_type;
+       ep->xfer_type = usb_pipetype(urb->pipe);
+       /* We use the fact that usb_pipein() returns 0x80 */
+       ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+       ep->devnum = usb_pipedevice(urb->pipe);
+       ep->busnum = rp->r.m_bus->u_bus->busnum;
+       ep->id = (unsigned long) urb;
+       ep->ts_sec = ts.tv_sec;
+       ep->ts_usec = ts.tv_usec;
+       ep->status = urb->status;
+       ep->len_urb = urb_length;
+       ep->len_cap = length;
+
+       ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type);
+       if (length != 0) {
+               ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
+               if (ep->flag_data != 0) {       /* Yes, it's 0x00, not '0' */
+                       ep->len_cap = 0;
+                       mon_buff_area_shrink(rp, length);
+               }
+       } else {
+               ep->flag_data = data_tag;
+       }
+
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+
+       wake_up(&rp->b_wait);
+}
+
+static void mon_bin_submit(void *data, struct urb *urb)
+{
+       struct mon_reader_bin *rp = data;
+       mon_bin_event(rp, urb, 'S');
+}
+
+static void mon_bin_complete(void *data, struct urb *urb)
+{
+       struct mon_reader_bin *rp = data;
+       mon_bin_event(rp, urb, 'C');
+}
+
+static void mon_bin_error(void *data, struct urb *urb, int error)
+{
+       struct mon_reader_bin *rp = data;
+       unsigned long flags;
+       unsigned int offset;
+       struct mon_bin_hdr *ep;
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+
+       offset = mon_buff_area_alloc(rp, PKT_SIZE);
+       if (offset == ~0) {
+               /* Not incrementing cnt_lost. Just because. */
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+               return;
+       }
+
+       ep = MON_OFF2HDR(rp, offset);
+
+       memset(ep, 0, PKT_SIZE);
+       ep->type = 'E';
+       ep->xfer_type = usb_pipetype(urb->pipe);
+       /* We use the fact that usb_pipein() returns 0x80 */
+       ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+       ep->devnum = usb_pipedevice(urb->pipe);
+       ep->busnum = rp->r.m_bus->u_bus->busnum;
+       ep->id = (unsigned long) urb;
+       ep->status = error;
+
+       ep->flag_setup = '-';
+       ep->flag_data = 'E';
+
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+
+       wake_up(&rp->b_wait);
+}
+
+static int mon_bin_open(struct inode *inode, struct file *file)
+{
+       struct mon_bus *mbus;
+       struct usb_bus *ubus;
+       struct mon_reader_bin *rp;
+       size_t size;
+       int rc;
+
+       mutex_lock(&mon_lock);
+       if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) {
+               mutex_unlock(&mon_lock);
+               return -ENODEV;
+       }
+       if ((ubus = mbus->u_bus) == NULL) {
+               printk(KERN_ERR TAG ": consistency error on open\n");
+               mutex_unlock(&mon_lock);
+               return -ENODEV;
+       }
+
+       rp = kzalloc(sizeof(struct mon_reader_bin), GFP_KERNEL);
+       if (rp == NULL) {
+               rc = -ENOMEM;
+               goto err_alloc;
+       }
+       spin_lock_init(&rp->b_lock);
+       init_waitqueue_head(&rp->b_wait);
+       mutex_init(&rp->fetch_lock);
+
+       rp->b_size = BUFF_DFL;
+
+       size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE);
+       if ((rp->b_vec = kzalloc(size, GFP_KERNEL)) == NULL) {
+               rc = -ENOMEM;
+               goto err_allocvec;
+       }
+
+       if ((rc = mon_alloc_buff(rp->b_vec, rp->b_size/CHUNK_SIZE)) < 0)
+               goto err_allocbuff;
+
+       rp->r.m_bus = mbus;
+       rp->r.r_data = rp;
+       rp->r.rnf_submit = mon_bin_submit;
+       rp->r.rnf_error = mon_bin_error;
+       rp->r.rnf_complete = mon_bin_complete;
+
+       mon_reader_add(mbus, &rp->r);
+
+       file->private_data = rp;
+       mutex_unlock(&mon_lock);
+       return 0;
+
+err_allocbuff:
+       kfree(rp->b_vec);
+err_allocvec:
+       kfree(rp);
+err_alloc:
+       mutex_unlock(&mon_lock);
+       return rc;
+}
+
+/*
+ * Extract an event from buffer and copy it to user space.
+ * Wait if there is no event ready.
+ * Returns zero or error.
+ */
+static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp,
+    struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes)
+{
+       unsigned long flags;
+       struct mon_bin_hdr *ep;
+       size_t step_len;
+       unsigned int offset;
+       int rc;
+
+       mutex_lock(&rp->fetch_lock);
+
+       if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+               mutex_unlock(&rp->fetch_lock);
+               return rc;
+       }
+
+       ep = MON_OFF2HDR(rp, rp->b_out);
+
+       if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) {
+               mutex_unlock(&rp->fetch_lock);
+               return -EFAULT;
+       }
+
+       step_len = min(ep->len_cap, nbytes);
+       if ((offset = rp->b_out + PKT_SIZE) >= rp->b_size) offset = 0;
+
+       if (copy_from_buf(rp, offset, data, step_len)) {
+               mutex_unlock(&rp->fetch_lock);
+               return -EFAULT;
+       }
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+       mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+       rp->b_read = 0;
+
+       mutex_unlock(&rp->fetch_lock);
+       return 0;
+}
+
+static int mon_bin_release(struct inode *inode, struct file *file)
+{
+       struct mon_reader_bin *rp = file->private_data;
+       struct mon_bus* mbus = rp->r.m_bus;
+
+       mutex_lock(&mon_lock);
+
+       if (mbus->nreaders <= 0) {
+               printk(KERN_ERR TAG ": consistency error on close\n");
+               mutex_unlock(&mon_lock);
+               return 0;
+       }
+       mon_reader_del(mbus, &rp->r);
+
+       mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE);
+       kfree(rp->b_vec);
+       kfree(rp);
+
+       mutex_unlock(&mon_lock);
+       return 0;
+}
+
+static ssize_t mon_bin_read(struct file *file, char __user *buf,
+    size_t nbytes, loff_t *ppos)
+{
+       struct mon_reader_bin *rp = file->private_data;
+       unsigned long flags;
+       struct mon_bin_hdr *ep;
+       unsigned int offset;
+       size_t step_len;
+       char *ptr;
+       ssize_t done = 0;
+       int rc;
+
+       mutex_lock(&rp->fetch_lock);
+
+       if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+               mutex_unlock(&rp->fetch_lock);
+               return rc;
+       }
+
+       ep = MON_OFF2HDR(rp, rp->b_out);
+
+       if (rp->b_read < sizeof(struct mon_bin_hdr)) {
+               step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read);
+               ptr = ((char *)ep) + rp->b_read;
+               if (step_len && copy_to_user(buf, ptr, step_len)) {
+                       mutex_unlock(&rp->fetch_lock);
+                       return -EFAULT;
+               }
+               nbytes -= step_len;
+               buf += step_len;
+               rp->b_read += step_len;
+               done += step_len;
+       }
+
+       if (rp->b_read >= sizeof(struct mon_bin_hdr)) {
+               step_len = min(nbytes, (size_t)ep->len_cap);
+               offset = rp->b_out + PKT_SIZE;
+               offset += rp->b_read - sizeof(struct mon_bin_hdr);
+               if (offset >= rp->b_size)
+                       offset -= rp->b_size;
+               if (copy_from_buf(rp, offset, buf, step_len)) {
+                       mutex_unlock(&rp->fetch_lock);
+                       return -EFAULT;
+               }
+               nbytes -= step_len;
+               buf += step_len;
+               rp->b_read += step_len;
+               done += step_len;
+       }
+
+       /*
+        * Check if whole packet was read, and if so, jump to the next one.
+        */
+       if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) {
+               spin_lock_irqsave(&rp->b_lock, flags);
+               mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+               rp->b_read = 0;
+       }
+
+       mutex_unlock(&rp->fetch_lock);
+       return done;
+}
+
+/*
+ * Remove at most nevents from chunked buffer.
+ * Returns the number of removed events.
+ */
+static int mon_bin_flush(struct mon_reader_bin *rp, unsigned nevents)
+{
+       unsigned long flags;
+       struct mon_bin_hdr *ep;
+       int i;
+
+       mutex_lock(&rp->fetch_lock);
+       spin_lock_irqsave(&rp->b_lock, flags);
+       for (i = 0; i < nevents; ++i) {
+               if (MON_RING_EMPTY(rp))
+                       break;
+
+               ep = MON_OFF2HDR(rp, rp->b_out);
+               mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+       }
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+       rp->b_read = 0;
+       mutex_unlock(&rp->fetch_lock);
+       return i;
+}
+
+/*
+ * Fetch at most max event offsets into the buffer and put them into vec.
+ * The events are usually freed later with mon_bin_flush.
+ * Return the effective number of events fetched.
+ */
+static int mon_bin_fetch(struct file *file, struct mon_reader_bin *rp,
+    u32 __user *vec, unsigned int max)
+{
+       unsigned int cur_out;
+       unsigned int bytes, avail;
+       unsigned int size;
+       unsigned int nevents;
+       struct mon_bin_hdr *ep;
+       unsigned long flags;
+       int rc;
+
+       mutex_lock(&rp->fetch_lock);
+
+       if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+               mutex_unlock(&rp->fetch_lock);
+               return rc;
+       }
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+       avail = rp->b_cnt;
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+
+       cur_out = rp->b_out;
+       nevents = 0;
+       bytes = 0;
+       while (bytes < avail) {
+               if (nevents >= max)
+                       break;
+
+               ep = MON_OFF2HDR(rp, cur_out);
+               if (put_user(cur_out, &vec[nevents])) {
+                       mutex_unlock(&rp->fetch_lock);
+                       return -EFAULT;
+               }
+
+               nevents++;
+               size = ep->len_cap + PKT_SIZE;
+               size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+               if ((cur_out += size) >= rp->b_size)
+                       cur_out -= rp->b_size;
+               bytes += size;
+       }
+
+       mutex_unlock(&rp->fetch_lock);
+       return nevents;
+}
+
+/*
+ * Count events. This is almost the same as the above mon_bin_fetch,
+ * only we do not store offsets into user vector, and we have no limit.
+ */
+static int mon_bin_queued(struct mon_reader_bin *rp)
+{
+       unsigned int cur_out;
+       unsigned int bytes, avail;
+       unsigned int size;
+       unsigned int nevents;
+       struct mon_bin_hdr *ep;
+       unsigned long flags;
+
+       mutex_lock(&rp->fetch_lock);
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+       avail = rp->b_cnt;
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+
+       cur_out = rp->b_out;
+       nevents = 0;
+       bytes = 0;
+       while (bytes < avail) {
+               ep = MON_OFF2HDR(rp, cur_out);
+
+               nevents++;
+               size = ep->len_cap + PKT_SIZE;
+               size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+               if ((cur_out += size) >= rp->b_size)
+                       cur_out -= rp->b_size;
+               bytes += size;
+       }
+
+       mutex_unlock(&rp->fetch_lock);
+       return nevents;
+}
+
+/*
+ */
+static int mon_bin_ioctl(struct inode *inode, struct file *file,
+    unsigned int cmd, unsigned long arg)
+{
+       struct mon_reader_bin *rp = file->private_data;
+       // struct mon_bus* mbus = rp->r.m_bus;
+       int ret = 0;
+       struct mon_bin_hdr *ep;
+       unsigned long flags;
+
+       switch (cmd) {
+
+       case MON_IOCQ_URB_LEN:
+               /*
+                * N.B. This only returns the size of data, without the header.
+                */
+               spin_lock_irqsave(&rp->b_lock, flags);
+               if (!MON_RING_EMPTY(rp)) {
+                       ep = MON_OFF2HDR(rp, rp->b_out);
+                       ret = ep->len_cap;
+               }
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+               break;
+
+       case MON_IOCQ_RING_SIZE:
+               ret = rp->b_size;
+               break;
+
+       case MON_IOCT_RING_SIZE:
+               /*
+                * Changing the buffer size will flush it's contents; the new
+                * buffer is allocated before releasing the old one to be sure
+                * the device will stay functional also in case of memory
+                * pressure.
+                */
+               {
+               int size;
+               struct mon_pgmap *vec;
+
+               if (arg < BUFF_MIN || arg > BUFF_MAX)
+                       return -EINVAL;
+
+               size = CHUNK_ALIGN(arg);
+               if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE),
+                   GFP_KERNEL)) == NULL) {
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               ret = mon_alloc_buff(vec, size/CHUNK_SIZE);
+               if (ret < 0) {
+                       kfree(vec);
+                       break;
+               }
+
+               mutex_lock(&rp->fetch_lock);
+               spin_lock_irqsave(&rp->b_lock, flags);
+               mon_free_buff(rp->b_vec, size/CHUNK_SIZE);
+               kfree(rp->b_vec);
+               rp->b_vec  = vec;
+               rp->b_size = size;
+               rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0;
+               rp->cnt_lost = 0;
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+               mutex_unlock(&rp->fetch_lock);
+               }
+               break;
+
+       case MON_IOCH_MFLUSH:
+               ret = mon_bin_flush(rp, arg);
+               break;
+
+       case MON_IOCX_GET:
+               {
+               struct mon_bin_get getb;
+
+               if (copy_from_user(&getb, (void __user *)arg,
+                                           sizeof(struct mon_bin_get)))
+                       return -EFAULT;
+
+               if (getb.alloc > 0x10000000)    /* Want to cast to u32 */
+                       return -EINVAL;
+               ret = mon_bin_get_event(file, rp,
+                         getb.hdr, getb.data, (unsigned int)getb.alloc);
+               }
+               break;
+
+#ifdef CONFIG_COMPAT
+       case MON_IOCX_GET32: {
+               struct mon_bin_get32 getb;
+
+               if (copy_from_user(&getb, (void __user *)arg,
+                                           sizeof(struct mon_bin_get32)))
+                       return -EFAULT;
+
+               ret = mon_bin_get_event(file, rp,
+                   compat_ptr(getb.hdr32), compat_ptr(getb.data32),
+                   getb.alloc32);
+               }
+               break;
+#endif
+
+       case MON_IOCX_MFETCH:
+               {
+               struct mon_bin_mfetch mfetch;
+               struct mon_bin_mfetch __user *uptr;
+
+               uptr = (struct mon_bin_mfetch __user *)arg;
+
+               if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+                       return -EFAULT;
+
+               if (mfetch.nflush) {
+                       ret = mon_bin_flush(rp, mfetch.nflush);
+                       if (ret < 0)
+                               return ret;
+                       if (put_user(ret, &uptr->nflush))
+                               return -EFAULT;
+               }
+               ret = mon_bin_fetch(file, rp, mfetch.offvec, mfetch.nfetch);
+               if (ret < 0)
+                       return ret;
+               if (put_user(ret, &uptr->nfetch))
+                       return -EFAULT;
+               ret = 0;
+               }
+               break;
+
+#ifdef CONFIG_COMPAT
+       case MON_IOCX_MFETCH32:
+               {
+               struct mon_bin_mfetch32 mfetch;
+               struct mon_bin_mfetch32 __user *uptr;
+
+               uptr = (struct mon_bin_mfetch32 __user *) compat_ptr(arg);
+
+               if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+                       return -EFAULT;
+
+               if (mfetch.nflush32) {
+                       ret = mon_bin_flush(rp, mfetch.nflush32);
+                       if (ret < 0)
+                               return ret;
+                       if (put_user(ret, &uptr->nflush32))
+                               return -EFAULT;
+               }
+               ret = mon_bin_fetch(file, rp, compat_ptr(mfetch.offvec32),
+                   mfetch.nfetch32);
+               if (ret < 0)
+                       return ret;
+               if (put_user(ret, &uptr->nfetch32))
+                       return -EFAULT;
+               ret = 0;
+               }
+               break;
+#endif
+
+       case MON_IOCG_STATS: {
+               struct mon_bin_stats __user *sp;
+               unsigned int nevents;
+               unsigned int ndropped;
+
+               spin_lock_irqsave(&rp->b_lock, flags);
+               ndropped = rp->cnt_lost;
+               rp->cnt_lost = 0;
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+               nevents = mon_bin_queued(rp);
+
+               sp = (struct mon_bin_stats __user *)arg;
+               if (put_user(rp->cnt_lost, &sp->dropped))
+                       return -EFAULT;
+               if (put_user(nevents, &sp->queued))
+                       return -EFAULT;
+
+               }
+               break;
+
+       default:
+               return -ENOTTY;
+       }
+
+       return ret;
+}
+
+static unsigned int
+mon_bin_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct mon_reader_bin *rp = file->private_data;
+       unsigned int mask = 0;
+       unsigned long flags;
+
+       if (file->f_mode & FMODE_READ)
+               poll_wait(file, &rp->b_wait, wait);
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+       if (!MON_RING_EMPTY(rp))
+               mask |= POLLIN | POLLRDNORM;    /* readable */
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+       return mask;
+}
+
+/*
+ * open and close: just keep track of how many times the device is
+ * mapped, to use the proper memory allocation function.
+ */
+static void mon_bin_vma_open(struct vm_area_struct *vma)
+{
+       struct mon_reader_bin *rp = vma->vm_private_data;
+       rp->mmap_active++;
+}
+
+static void mon_bin_vma_close(struct vm_area_struct *vma)
+{
+       struct mon_reader_bin *rp = vma->vm_private_data;
+       rp->mmap_active--;
+}
+
+/*
+ * Map ring pages to user space.
+ */
+struct page *mon_bin_vma_nopage(struct vm_area_struct *vma,
+                                unsigned long address, int *type)
+{
+       struct mon_reader_bin *rp = vma->vm_private_data;
+       unsigned long offset, chunk_idx;
+       struct page *pageptr;
+
+       offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+       if (offset >= rp->b_size)
+               return NOPAGE_SIGBUS;
+       chunk_idx = offset / CHUNK_SIZE;
+       pageptr = rp->b_vec[chunk_idx].pg;
+       get_page(pageptr);
+       if (type)
+               *type = VM_FAULT_MINOR;
+       return pageptr;
+}
+
+struct vm_operations_struct mon_bin_vm_ops = {
+       .open =     mon_bin_vma_open,
+       .close =    mon_bin_vma_close,
+       .nopage =   mon_bin_vma_nopage,
+};
+
+int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       /* don't do anything here: "nopage" will set up page table entries */
+       vma->vm_ops = &mon_bin_vm_ops;
+       vma->vm_flags |= VM_RESERVED;
+       vma->vm_private_data = filp->private_data;
+       mon_bin_vma_open(vma);
+       return 0;
+}
+
+struct file_operations mon_fops_binary = {
+       .owner =        THIS_MODULE,
+       .open =         mon_bin_open,
+       .llseek =       no_llseek,
+       .read =         mon_bin_read,
+       /* .write =     mon_text_write, */
+       .poll =         mon_bin_poll,
+       .ioctl =        mon_bin_ioctl,
+       .release =      mon_bin_release,
+};
+
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp)
+{
+       DECLARE_WAITQUEUE(waita, current);
+       unsigned long flags;
+
+       add_wait_queue(&rp->b_wait, &waita);
+       set_current_state(TASK_INTERRUPTIBLE);
+
+       spin_lock_irqsave(&rp->b_lock, flags);
+       while (MON_RING_EMPTY(rp)) {
+               spin_unlock_irqrestore(&rp->b_lock, flags);
+
+               if (file->f_flags & O_NONBLOCK) {
+                       set_current_state(TASK_RUNNING);
+                       remove_wait_queue(&rp->b_wait, &waita);
+                       return -EWOULDBLOCK; /* Same as EAGAIN in Linux */
+               }
+               schedule();
+               if (signal_pending(current)) {
+                       remove_wait_queue(&rp->b_wait, &waita);
+                       return -EINTR;
+               }
+               set_current_state(TASK_INTERRUPTIBLE);
+
+               spin_lock_irqsave(&rp->b_lock, flags);
+       }
+       spin_unlock_irqrestore(&rp->b_lock, flags);
+
+       set_current_state(TASK_RUNNING);
+       remove_wait_queue(&rp->b_wait, &waita);
+       return 0;
+}
+
+static int mon_alloc_buff(struct mon_pgmap *map, int npages)
+{
+       int n;
+       unsigned long vaddr;
+
+       for (n = 0; n < npages; n++) {
+               vaddr = get_zeroed_page(GFP_KERNEL);
+               if (vaddr == 0) {
+                       while (n-- != 0)
+                               free_page((unsigned long) map[n].ptr);
+                       return -ENOMEM;
+               }
+               map[n].ptr = (unsigned char *) vaddr;
+               map[n].pg = virt_to_page(vaddr);
+       }
+       return 0;
+}
+
+static void mon_free_buff(struct mon_pgmap *map, int npages)
+{
+       int n;
+
+       for (n = 0; n < npages; n++)
+               free_page((unsigned long) map[n].ptr);
+}
+
+int __init mon_bin_init(void)
+{
+       int rc;
+
+       rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon");
+       if (rc < 0)
+               goto err_dev;
+
+       cdev_init(&mon_bin_cdev, &mon_fops_binary);
+       mon_bin_cdev.owner = THIS_MODULE;
+
+       rc = cdev_add(&mon_bin_cdev, mon_bin_dev0, MON_BIN_MAX_MINOR);
+       if (rc < 0)
+               goto err_add;
+
+       return 0;
+
+err_add:
+       unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+err_dev:
+       return rc;
+}
+
+void __exit mon_bin_exit(void)
+{
+       cdev_del(&mon_bin_cdev);
+       unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+}
index ddcfc01..140cc80 100644 (file)
@@ -48,6 +48,36 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
        local_irq_restore(flags);
        return 0;
 }
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+       unsigned long flags;
+       unsigned int step_len;
+       struct page *pg;
+       unsigned char *map;
+       unsigned long page_off, page_len;
+
+       local_irq_save(flags);
+       while (length) {
+               /* compute number of bytes we are going to copy in this page */
+               step_len = length;
+               page_off = dma_addr & (PAGE_SIZE-1);
+               page_len = PAGE_SIZE - page_off;
+               if (page_len < step_len)
+                       step_len = page_len;
+
+               /* copy data and advance pointers */
+               pg = phys_to_page(dma_addr);
+               map = kmap_atomic(pg, KM_IRQ0);
+               offset = mon_copy_to_buff(rp, offset, map + page_off, step_len);
+               kunmap_atomic(map, KM_IRQ0);
+               dma_addr += step_len;
+               length -= step_len;
+       }
+       local_irq_restore(flags);
+}
+
 #endif /* __i386__ */
 
 #ifndef MON_HAS_UNMAP
@@ -55,4 +85,11 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
 {
        return 'D';
 }
-#endif
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+       ;
+}
+
+#endif /* MON_HAS_UNMAP */
index 394bbf2..c9739e7 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb.h>
-#include <linux/debugfs.h>
 #include <linux/smp_lock.h>
 #include <linux/notifier.h>
 #include <linux/mutex.h>
@@ -22,11 +21,10 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb);
 static void mon_stop(struct mon_bus *mbus);
 static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
 static void mon_bus_drop(struct kref *r);
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
+static void mon_bus_init(struct usb_bus *ubus);
 
 DEFINE_MUTEX(mon_lock);
 
-static struct dentry *mon_dir;         /* /dbg/usbmon */
 static LIST_HEAD(mon_buses);           /* All buses we know: struct mon_bus */
 
 /*
@@ -200,7 +198,7 @@ static void mon_stop(struct mon_bus *mbus)
  */
 static void mon_bus_add(struct usb_bus *ubus)
 {
-       mon_bus_init(mon_dir, ubus);
+       mon_bus_init(ubus);
 }
 
 /*
@@ -212,8 +210,8 @@ static void mon_bus_remove(struct usb_bus *ubus)
 
        mutex_lock(&mon_lock);
        list_del(&mbus->bus_link);
-       debugfs_remove(mbus->dent_t);
-       debugfs_remove(mbus->dent_s);
+       if (mbus->text_inited)
+               mon_text_del(mbus);
 
        mon_dissolve(mbus, ubus);
        kref_put(&mbus->ref, mon_bus_drop);
@@ -281,13 +279,9 @@ static void mon_bus_drop(struct kref *r)
  *  - refcount USB bus struct
  *  - link
  */
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
+static void mon_bus_init(struct usb_bus *ubus)
 {
-       struct dentry *d;
        struct mon_bus *mbus;
-       enum { NAMESZ = 10 };
-       char name[NAMESZ];
-       int rc;
 
        if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
                goto err_alloc;
@@ -303,57 +297,54 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
        ubus->mon_bus = mbus;
        mbus->uses_dma = ubus->uses_dma;
 
-       rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
-       if (rc <= 0 || rc >= NAMESZ)
-               goto err_print_t;
-       d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text);
-       if (d == NULL)
-               goto err_create_t;
-       mbus->dent_t = d;
-
-       rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
-       if (rc <= 0 || rc >= NAMESZ)
-               goto err_print_s;
-       d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat);
-       if (d == NULL)
-               goto err_create_s;
-       mbus->dent_s = d;
+       mbus->text_inited = mon_text_add(mbus, ubus);
+       // mon_bin_add(...)
 
        mutex_lock(&mon_lock);
        list_add_tail(&mbus->bus_link, &mon_buses);
        mutex_unlock(&mon_lock);
        return;
 
-err_create_s:
-err_print_s:
-       debugfs_remove(mbus->dent_t);
-err_create_t:
-err_print_t:
-       kfree(mbus);
 err_alloc:
        return;
 }
 
+/*
+ * Search a USB bus by number. Notice that USB bus numbers start from one,
+ * which we may later use to identify "all" with zero.
+ *
+ * This function must be called with mon_lock held.
+ *
+ * This is obviously inefficient and may be revised in the future.
+ */
+struct mon_bus *mon_bus_lookup(unsigned int num)
+{
+       struct list_head *p;
+       struct mon_bus *mbus;
+
+       list_for_each (p, &mon_buses) {
+               mbus = list_entry(p, struct mon_bus, bus_link);
+               if (mbus->u_bus->busnum == num) {
+                       return mbus;
+               }
+       }
+       return NULL;
+}
+
 static int __init mon_init(void)
 {
        struct usb_bus *ubus;
-       struct dentry *mondir;
+       int rc;
 
-       mondir = debugfs_create_dir("usbmon", NULL);
-       if (IS_ERR(mondir)) {
-               printk(KERN_NOTICE TAG ": debugfs is not available\n");
-               return -ENODEV;
-       }
-       if (mondir == NULL) {
-               printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
-               return -ENODEV;
-       }
-       mon_dir = mondir;
+       if ((rc = mon_text_init()) != 0)
+               goto err_text;
+       if ((rc = mon_bin_init()) != 0)
+               goto err_bin;
 
        if (usb_mon_register(&mon_ops_0) != 0) {
                printk(KERN_NOTICE TAG ": unable to register with the core\n");
-               debugfs_remove(mondir);
-               return -ENODEV;
+               rc = -ENODEV;
+               goto err_reg;
        }
        // MOD_INC_USE_COUNT(which_module?);
 
@@ -361,10 +352,17 @@ static int __init mon_init(void)
 
        mutex_lock(&usb_bus_list_lock);
        list_for_each_entry (ubus, &usb_bus_list, bus_list) {
-               mon_bus_init(mondir, ubus);
+               mon_bus_init(ubus);
        }
        mutex_unlock(&usb_bus_list_lock);
        return 0;
+
+err_reg:
+       mon_bin_exit();
+err_bin:
+       mon_text_exit();
+err_text:
+       return rc;
 }
 
 static void __exit mon_exit(void)
@@ -381,8 +379,8 @@ static void __exit mon_exit(void)
                mbus = list_entry(p, struct mon_bus, bus_link);
                list_del(p);
 
-               debugfs_remove(mbus->dent_t);
-               debugfs_remove(mbus->dent_s);
+               if (mbus->text_inited)
+                       mon_text_del(mbus);
 
                /*
                 * This never happens, because the open/close paths in
@@ -401,7 +399,8 @@ static void __exit mon_exit(void)
        }
        mutex_unlock(&mon_lock);
 
-       debugfs_remove(mon_dir);
+       mon_text_exit();
+       mon_bin_exit();
 }
 
 module_init(mon_init);
index 05cf2c9..d38a127 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/usb.h>
 #include <linux/time.h>
 #include <linux/mutex.h>
+#include <linux/debugfs.h>
 #include <asm/uaccess.h>
 
 #include "usb_mon.h"
@@ -63,6 +64,8 @@ struct mon_reader_text {
        char slab_name[SLAB_NAME_SZ];
 };
 
+static struct dentry *mon_dir;         /* Usually /sys/kernel/debug/usbmon */
+
 static void mon_text_ctor(void *, struct kmem_cache *, unsigned long);
 
 /*
@@ -436,7 +439,7 @@ static int mon_text_release(struct inode *inode, struct file *file)
        return 0;
 }
 
-const struct file_operations mon_fops_text = {
+static const struct file_operations mon_fops_text = {
        .owner =        THIS_MODULE,
        .open =         mon_text_open,
        .llseek =       no_llseek,
@@ -447,6 +450,47 @@ const struct file_operations mon_fops_text = {
        .release =      mon_text_release,
 };
 
+int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
+{
+       struct dentry *d;
+       enum { NAMESZ = 10 };
+       char name[NAMESZ];
+       int rc;
+
+       rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
+       if (rc <= 0 || rc >= NAMESZ)
+               goto err_print_t;
+       d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text);
+       if (d == NULL)
+               goto err_create_t;
+       mbus->dent_t = d;
+
+       /* XXX The stats do not belong to here (text API), but oh well... */
+       rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
+       if (rc <= 0 || rc >= NAMESZ)
+               goto err_print_s;
+       d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat);
+       if (d == NULL)
+               goto err_create_s;
+       mbus->dent_s = d;
+
+       return 1;
+
+err_create_s:
+err_print_s:
+       debugfs_remove(mbus->dent_t);
+       mbus->dent_t = NULL;
+err_create_t:
+err_print_t:
+       return 0;
+}
+
+void mon_text_del(struct mon_bus *mbus)
+{
+       debugfs_remove(mbus->dent_t);
+       debugfs_remove(mbus->dent_s);
+}
+
 /*
  * Slab interface: constructor.
  */
@@ -459,3 +503,24 @@ static void mon_text_ctor(void *mem, struct kmem_cache *slab, unsigned long sfla
        memset(mem, 0xe5, sizeof(struct mon_event_text));
 }
 
+int __init mon_text_init(void)
+{
+       struct dentry *mondir;
+
+       mondir = debugfs_create_dir("usbmon", NULL);
+       if (IS_ERR(mondir)) {
+               printk(KERN_NOTICE TAG ": debugfs is not available\n");
+               return -ENODEV;
+       }
+       if (mondir == NULL) {
+               printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
+               return -ENODEV;
+       }
+       mon_dir = mondir;
+       return 0;
+}
+
+void __exit mon_text_exit(void)
+{
+       debugfs_remove(mon_dir);
+}
index ab9d02d..4f949ce 100644 (file)
 struct mon_bus {
        struct list_head bus_link;
        spinlock_t lock;
+       struct usb_bus *u_bus;
+
+       int text_inited;
        struct dentry *dent_s;          /* Debugging file */
        struct dentry *dent_t;          /* Text interface file */
-       struct usb_bus *u_bus;
        int uses_dma;
 
        /* Ref */
@@ -48,13 +50,35 @@ struct mon_reader {
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
 void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
 
+struct mon_bus *mon_bus_lookup(unsigned int num);
+
+int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
+void mon_text_del(struct mon_bus *mbus);
+// void mon_bin_add(struct mon_bus *);
+
+int __init mon_text_init(void);
+void __exit mon_text_exit(void);
+int __init mon_bin_init(void);
+void __exit mon_bin_exit(void);
+
 /*
- */
+ * DMA interface.
+ *
+ * XXX The vectored side needs a serious re-thinking. Abstracting vectors,
+ * like in Paolo's original patch, produces a double pkmap. We need an idea.
+*/
 extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
 
+struct mon_reader_bin;
+extern void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int len);
+extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp,
+    unsigned int offset, const unsigned char *from, unsigned int len);
+
+/*
+ */
 extern struct mutex mon_lock;
 
-extern const struct file_operations mon_fops_text;
 extern const struct file_operations mon_fops_stat;
 
 #endif /* __USB_MON_H */
index e081836..a2b94ef 100644 (file)
@@ -222,13 +222,15 @@ config USB_NET_MCS7830
          adapters marketed under the DeLOCK brand.
 
 config USB_NET_RNDIS_HOST
-       tristate "Host for RNDIS devices (EXPERIMENTAL)"
+       tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)"
        depends on USB_USBNET && EXPERIMENTAL
        select USB_NET_CDCETHER
        help
          This option enables hosting "Remote NDIS" USB networking links,
          as encouraged by Microsoft (instead of CDC Ethernet!) for use in
-         various devices that may only support this protocol.
+         various devices that may only support this protocol.  A variant
+         of this protocol (with even less public documentation) seems to
+         be at the root of Microsoft's "ActiveSync" too.
 
          Avoid using this protocol unless you have no better options.
          The protocol specification is incomplete, and is controlled by
index 896449f..4206df2 100644 (file)
@@ -1449,6 +1449,10 @@ static const struct usb_device_id        products [] = {
        // Linksys USB1000
        USB_DEVICE (0x1737, 0x0039),
        .driver_info = (unsigned long) &ax88178_info,
+}, {
+       // IO-DATA ETG-US2
+       USB_DEVICE (0x04bb, 0x0930),
+       .driver_info = (unsigned long) &ax88178_info,
 },
        { },            // END
 };
index 44a9154..e5cdafa 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * CDC Ethernet based networking peripherals
  * Copyright (C) 2003-2005 by David Brownell
+ * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 #include "usbnet.h"
 
 
+#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
+
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+       return desc->bInterfaceClass == USB_CLASS_COMM
+               && desc->bInterfaceSubClass == 2
+               && desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+       return desc->bInterfaceClass == USB_CLASS_MISC
+               && desc->bInterfaceSubClass == 1
+               && desc->bInterfaceProtocol == 1;
+}
+
+#else
+
+#define is_rndis(desc)         0
+#define is_activesync(desc)    0
+
+#endif
+
 /*
  * probes control interface, claims data interface, collects the bulk
  * endpoints, activates data interface (if needed), maybe sets MTU.
@@ -71,7 +95,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
        /* this assumes that if there's a non-RNDIS vendor variant
         * of cdc-acm, it'll fail RNDIS requests cleanly.
         */
-       rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
+       rndis = is_rndis(&intf->cur_altsetting->desc)
+               || is_activesync(&intf->cur_altsetting->desc);
 
        memset(info, 0, sizeof *info);
        info->control = intf;
@@ -99,6 +124,23 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
                                goto bad_desc;
                        }
                        break;
+               case USB_CDC_ACM_TYPE:
+                       /* paranoia:  disambiguate a "real" vendor-specific
+                        * modem interface from an RNDIS non-modem.
+                        */
+                       if (rndis) {
+                               struct usb_cdc_acm_descriptor *d;
+
+                               d = (void *) buf;
+                               if (d->bmCapabilities) {
+                                       dev_dbg(&intf->dev,
+                                               "ACM capabilities %02x, "
+                                               "not really RNDIS?\n",
+                                               d->bmCapabilities);
+                                       goto bad_desc;
+                               }
+                       }
+                       break;
                case USB_CDC_UNION_TYPE:
                        if (info->u) {
                                dev_dbg(&intf->dev, "extra CDC union\n");
@@ -171,7 +213,21 @@ next_desc:
                buf += buf [0];
        }
 
-       if (!info->header || !info->u || (!rndis && !info->ether)) {
+       /* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
+        * so we'll hard-wire the interfaces and not check for descriptors.
+        */
+       if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
+               info->control = usb_ifnum_to_if(dev->udev, 0);
+               info->data = usb_ifnum_to_if(dev->udev, 1);
+               if (!info->control || !info->data) {
+                       dev_dbg(&intf->dev,
+                               "activesync: master #0/%p slave #1/%p\n",
+                               info->control,
+                               info->data);
+                       goto bad_desc;
+               }
+
+       } else if (!info->header || !info->u || (!rndis && !info->ether)) {
                dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
                        info->header ? "" : "header ",
                        info->u ? "" : "union ",
index fa78326..36a9891 100644 (file)
@@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = {
        .suspend =      kaweth_suspend,
        .resume =       kaweth_resume,
        .id_table =     usb_klsi_table,
+       .supports_autosuspend = 1,
 };
 
 typedef __u8 eth_addr_t[6];
@@ -225,6 +226,7 @@ struct kaweth_device
        struct delayed_work lowmem_work;
 
        struct usb_device *dev;
+       struct usb_interface *intf;
        struct net_device *net;
        wait_queue_head_t term_wait;
 
@@ -662,9 +664,14 @@ static int kaweth_open(struct net_device *net)
 
        dbg("Opening network device.");
 
+       res = usb_autopm_get_interface(kaweth->intf);
+       if (res) {
+               err("Interface cannot be resumed.");
+               return -EIO;
+       }
        res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
        if (res)
-               return -EIO;
+               goto err_out;
 
        usb_fill_int_urb(
                kaweth->irq_urb,
@@ -681,7 +688,7 @@ static int kaweth_open(struct net_device *net)
        res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
        if (res) {
                usb_kill_urb(kaweth->rx_urb);
-               return -EIO;
+               goto err_out;
        }
        kaweth->opened = 1;
 
@@ -689,10 +696,14 @@ static int kaweth_open(struct net_device *net)
 
        kaweth_async_set_rx_mode(kaweth);
        return 0;
+
+err_out:
+       usb_autopm_enable(kaweth->intf);
+       return -EIO;
 }
 
 /****************************************************************
- *     kaweth_close
+ *     kaweth_kill_urbs
  ****************************************************************/
 static void kaweth_kill_urbs(struct kaweth_device *kaweth)
 {
@@ -724,17 +735,29 @@ static int kaweth_close(struct net_device *net)
 
        kaweth->status &= ~KAWETH_STATUS_CLOSING;
 
+       usb_autopm_enable(kaweth->intf);
+
        return 0;
 }
 
 static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
+       struct kaweth_device *kaweth = netdev_priv(dev);
 
        strlcpy(info->driver, driver_name, sizeof(info->driver));
+       usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info));
+}
+
+static u32 kaweth_get_link(struct net_device *dev)
+{
+       struct kaweth_device *kaweth = netdev_priv(dev);
+
+       return kaweth->linkstate;
 }
 
 static struct ethtool_ops ops = {
-       .get_drvinfo = kaweth_get_drvinfo
+       .get_drvinfo    = kaweth_get_drvinfo,
+       .get_link       = kaweth_get_link
 };
 
 /****************************************************************
@@ -908,6 +931,7 @@ static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
        struct kaweth_device *kaweth = usb_get_intfdata(intf);
        unsigned long flags;
 
+       dbg("Suspending device");
        spin_lock_irqsave(&kaweth->device_lock, flags);
        kaweth->status |= KAWETH_STATUS_SUSPENDING;
        spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -924,6 +948,7 @@ static int kaweth_resume(struct usb_interface *intf)
        struct kaweth_device *kaweth = usb_get_intfdata(intf);
        unsigned long flags;
 
+       dbg("Resuming device");
        spin_lock_irqsave(&kaweth->device_lock, flags);
        kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
        spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -1086,6 +1111,8 @@ err_fw:
 
        dbg("Initializing net device.");
 
+       kaweth->intf = intf;
+
        kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!kaweth->tx_urb)
                goto err_free_netdev;
@@ -1265,7 +1292,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
 {
         struct urb *urb;
         int retv;
-        int length;
+        int length = 0; /* shut up GCC */
 
         urb = usb_alloc_urb(0, GFP_NOIO);
         if (!urb)
index 98f6898..c746782 100644 (file)
@@ -214,9 +214,9 @@ PEGASUS_DEV( "Billionton USBEL-100", VENDOR_BILLIONTON, 0x0988,
                DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "Billionton USBE-100", VENDOR_BILLIONTON, 0x8511,
                DEFAULT_GPIO_RESET | PEGASUS_II )
-PEGASUS_DEV( "Corega FEter USB-TX", VENDOR_COREGA, 0x0004,
+PEGASUS_DEV( "Corega FEther USB-TX", VENDOR_COREGA, 0x0004,
                DEFAULT_GPIO_RESET )
-PEGASUS_DEV( "Corega FEter USB-TXS", VENDOR_COREGA, 0x000d,
+PEGASUS_DEV( "Corega FEther USB-TXS", VENDOR_COREGA, 0x000d,
                DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "D-Link DSB-650TX", VENDOR_DLINK, 0x4001,
                DEFAULT_GPIO_RESET )
index a322a16..be888d2 100644 (file)
@@ -49,6 +49,8 @@
  *    - In some cases, MS-Windows will emit undocumented requests; this
  *     matters more to peripheral implementations than host ones.
  *
+ * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync".
+ *
  * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in
  * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and
  * currently rare) "Ethernet Emulation Model" (EEM).
@@ -61,6 +63,9 @@
  *  - control-in:  GET_ENCAPSULATED
  *
  * We'll try to ignore the RESPONSE_AVAILABLE notifications.
+ *
+ * REVISIT some RNDIS implementations seem to have curious issues still
+ * to be resolved.
  */
 struct rndis_msg_hdr {
        __le32  msg_type;                       /* RNDIS_MSG_* */
@@ -71,8 +76,14 @@ struct rndis_msg_hdr {
        // ... and more
 } __attribute__ ((packed));
 
-/* RNDIS defines this (absurdly huge) control timeout */
-#define        RNDIS_CONTROL_TIMEOUT_MS        (10 * 1000)
+/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
+#define        CONTROL_BUFFER_SIZE             1025
+
+/* RNDIS defines an (absurdly huge) 10 second control timeout,
+ * but ActiveSync seems to use a more usual 5 second timeout
+ * (which matches the USB 2.0 spec).
+ */
+#define        RNDIS_CONTROL_TIMEOUT_MS        (5 * 1000)
 
 
 #define ccpu2 __constant_cpu_to_le32
@@ -270,6 +281,7 @@ static void rndis_status(struct usbnet *dev, struct urb *urb)
 static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
 {
        struct cdc_state        *info = (void *) &dev->data;
+       int                     master_ifnum;
        int                     retval;
        unsigned                count;
        __le32                  rsp;
@@ -279,7 +291,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
         * disconnect(): either serialize, or dispatch responses on xid
         */
 
-       /* Issue the request; don't bother byteswapping our xid */
+       /* Issue the request; xid is unique, don't bother byteswapping it */
        if (likely(buf->msg_type != RNDIS_MSG_HALT
                        && buf->msg_type != RNDIS_MSG_RESET)) {
                xid = dev->xid++;
@@ -287,11 +299,12 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
                        xid = dev->xid++;
                buf->request_id = (__force __le32) xid;
        }
+       master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber;
        retval = usb_control_msg(dev->udev,
                usb_sndctrlpipe(dev->udev, 0),
                USB_CDC_SEND_ENCAPSULATED_COMMAND,
                USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               0, info->u->bMasterInterface0,
+               0, master_ifnum,
                buf, le32_to_cpu(buf->msg_len),
                RNDIS_CONTROL_TIMEOUT_MS);
        if (unlikely(retval < 0 || xid == 0))
@@ -306,13 +319,13 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
         */
        rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
        for (count = 0; count < 10; count++) {
-               memset(buf, 0, 1024);
+               memset(buf, 0, CONTROL_BUFFER_SIZE);
                retval = usb_control_msg(dev->udev,
                        usb_rcvctrlpipe(dev->udev, 0),
                        USB_CDC_GET_ENCAPSULATED_RESPONSE,
                        USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       0, info->u->bMasterInterface0,
-                       buf, 1024,
+                       0, master_ifnum,
+                       buf, CONTROL_BUFFER_SIZE,
                        RNDIS_CONTROL_TIMEOUT_MS);
                if (likely(retval >= 8)) {
                        msg_len = le32_to_cpu(buf->msg_len);
@@ -350,7 +363,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
                                        usb_sndctrlpipe(dev->udev, 0),
                                        USB_CDC_SEND_ENCAPSULATED_COMMAND,
                                        USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                                       0, info->u->bMasterInterface0,
+                                       0, master_ifnum,
                                        msg, sizeof *msg,
                                        RNDIS_CONTROL_TIMEOUT_MS);
                                if (unlikely(retval < 0))
@@ -393,38 +406,64 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
        u32                     tmp;
 
        /* we can't rely on i/o from stack working, or stack allocation */
-       u.buf = kmalloc(1024, GFP_KERNEL);
+       u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
        if (!u.buf)
                return -ENOMEM;
        retval = usbnet_generic_cdc_bind(dev, intf);
        if (retval < 0)
                goto fail;
 
-       net->hard_header_len += sizeof (struct rndis_data_hdr);
-
-       /* initialize; max transfer is 16KB at full speed */
        u.init->msg_type = RNDIS_MSG_INIT;
        u.init->msg_len = ccpu2(sizeof *u.init);
        u.init->major_version = ccpu2(1);
        u.init->minor_version = ccpu2(0);
-       u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len);
 
+       /* max transfer (in spec) is 0x4000 at full speed, but for
+        * TX we'll stick to one Ethernet packet plus RNDIS framing.
+        * For RX we handle drivers that zero-pad to end-of-packet.
+        * Don't let userspace change these settings.
+        */
+       net->hard_header_len += sizeof (struct rndis_data_hdr);
+       dev->hard_mtu = net->mtu + net->hard_header_len;
+
+       dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
+       dev->rx_urb_size &= ~(dev->maxpacket - 1);
+       u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);
+
+       net->change_mtu = NULL;
        retval = rndis_command(dev, u.header);
        if (unlikely(retval < 0)) {
                /* it might not even be an RNDIS device!! */
                dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
+               goto fail_and_release;
+       }
+       tmp = le32_to_cpu(u.init_c->max_transfer_size);
+       if (tmp < dev->hard_mtu) {
+               dev_err(&intf->dev,
+                       "dev can't take %u byte packets (max %u)\n",
+                       dev->hard_mtu, tmp);
                goto fail_and_release;
        }
-       dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size);
+
        /* REVISIT:  peripheral "alignment" request is ignored ... */
-       dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
+       dev_dbg(&intf->dev,
+               "hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
+               dev->hard_mtu, tmp, dev->rx_urb_size,
                1 << le32_to_cpu(u.init_c->packet_alignment));
 
-       /* get designated host ethernet address */
-       memset(u.get, 0, sizeof *u.get);
+       /* Get designated host ethernet address.
+        *
+        * Adding a payload exactly the same size as the expected response
+        * payload is an evident requirement MSFT added for ActiveSync.
+        * This undocumented (and nonsensical) issue was found by sniffing
+        * protocol requests from the ActiveSync 4.1 Windows driver.
+        */
+       memset(u.get, 0, sizeof *u.get + 48);
        u.get->msg_type = RNDIS_MSG_QUERY;
-       u.get->msg_len = ccpu2(sizeof *u.get);
+       u.get->msg_len = ccpu2(sizeof *u.get + 48);
        u.get->oid = OID_802_3_PERMANENT_ADDRESS;
+       u.get->len = ccpu2(48);
+       u.get->offset = ccpu2(20);
 
        retval = rndis_command(dev, u.header);
        if (unlikely(retval < 0)) {
@@ -432,7 +471,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
                goto fail_and_release;
        }
        tmp = le32_to_cpu(u.get_c->offset);
-       if (unlikely((tmp + 8) > (1024 - ETH_ALEN)
+       if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN)
                        || u.get_c->len != ccpu2(ETH_ALEN))) {
                dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
                        tmp, le32_to_cpu(u.get_c->len));
@@ -598,6 +637,10 @@ static const struct usb_device_id  products [] = {
        /* RNDIS is MSFT's un-official variant of CDC ACM */
        USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
        .driver_info = (unsigned long) &rndis_info,
+}, {
+       /* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
+       USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
+       .driver_info = (unsigned long) &rndis_info,
 },
        { },            // END
 };
index 86bcf63..11dad42 100644 (file)
@@ -572,8 +572,20 @@ static void aircable_unthrottle(struct usb_serial_port *port)
                schedule_work(&priv->rx_work);
 }
 
+static struct usb_driver aircable_driver = {
+       .name =         "aircable",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     id_table,
+       .no_dynamic_id =        1,
+};
+
 static struct usb_serial_driver aircable_device = {
-       .description =          "aircable",
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "aircable",
+       },
+       .usb_driver =           &aircable_driver,
        .id_table =             id_table,
        .num_ports =            1,
        .attach =               aircable_attach,
@@ -587,13 +599,6 @@ static struct usb_serial_driver aircable_device = {
        .unthrottle =           aircable_unthrottle,
 };
 
-static struct usb_driver aircable_driver = {
-       .name =         "aircable",
-       .probe =        usb_serial_probe,
-       .disconnect =   usb_serial_disconnect,
-       .id_table =     id_table,
-};
-
 static int __init aircable_init (void)
 {
        int retval;
index f2ca76a..0af42e3 100644 (file)
@@ -277,6 +277,7 @@ static struct usb_serial_driver airprime_device = {
                .owner =        THIS_MODULE,
                .name =         "airprime",
        },
+       .usb_driver =           &airprime_driver,
        .id_table =             id_table,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
index 5261cd2..edd6857 100644 (file)
@@ -444,6 +444,7 @@ static struct usb_driver ark3116_driver = {
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     id_table,
+       .no_dynamic_id =        1,
 };
 
 static struct usb_serial_driver ark3116_device = {
@@ -452,6 +453,7 @@ static struct usb_serial_driver ark3116_device = {
                .name =         "ark3116",
        },
        .id_table =             id_table,
+       .usb_driver =           &ark3116_driver,
        .num_interrupt_in =     1,
        .num_bulk_in =          1,
        .num_bulk_out =         1,
index 38b4dae..3b800d2 100644 (file)
@@ -126,6 +126,7 @@ static struct usb_serial_driver belkin_device = {
                .name =         "belkin",
        },
        .description =          "Belkin / Peracom / GoHubs USB Serial Adapter",
+       .usb_driver =           &belkin_driver,
        .id_table =             id_table_combined,
        .num_interrupt_in =     1,
        .num_bulk_in =          1,
index 6542f22..c08a384 100644 (file)
@@ -103,11 +103,52 @@ exit:
        return retval;
 }
 
+#ifdef CONFIG_HOTPLUG
+static ssize_t store_new_id(struct device_driver *driver,
+                           const char *buf, size_t count)
+{
+       struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
+       ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+
+       if (retval >= 0 && usb_drv->usb_driver != NULL)
+               retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
+                                         &usb_drv->usb_driver->drvwrap.driver,
+                                         buf, count);
+       return retval;
+}
+
+static struct driver_attribute drv_attrs[] = {
+       __ATTR(new_id, S_IWUSR, NULL, store_new_id),
+       __ATTR_NULL,
+};
+
+static void free_dynids(struct usb_serial_driver *drv)
+{
+       struct usb_dynid *dynid, *n;
+
+       spin_lock(&drv->dynids.lock);
+       list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
+               list_del(&dynid->node);
+               kfree(dynid);
+       }
+       spin_unlock(&drv->dynids.lock);
+}
+
+#else
+static struct driver_attribute drv_attrs[] = {
+       __ATTR_NULL,
+};
+static inline void free_dynids(struct usb_driver *drv)
+{
+}
+#endif
+
 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,
+       .drv_attrs =    drv_attrs,
 };
 
 int usb_serial_bus_register(struct usb_serial_driver *driver)
@@ -115,6 +156,9 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
        int retval;
 
        driver->driver.bus = &usb_serial_bus_type;
+       spin_lock_init(&driver->dynids.lock);
+       INIT_LIST_HEAD(&driver->dynids.list);
+
        retval = driver_register(&driver->driver);
 
        return retval;
@@ -122,6 +166,7 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
 
 void usb_serial_bus_deregister(struct usb_serial_driver *driver)
 {
+       free_dynids(driver);
        driver_unregister(&driver->driver);
 }
 
index 7ebaffd..06b4fff 100644 (file)
@@ -89,6 +89,7 @@ static struct usb_serial_driver cp2101_device = {
                .owner =        THIS_MODULE,
                .name =         "cp2101",
        },
+       .usb_driver             = &cp2101_driver,
        .id_table               = id_table,
        .num_interrupt_in       = 0,
        .num_bulk_in            = 0,
index a63c328..4167753 100644 (file)
@@ -88,6 +88,7 @@ static struct usb_serial_driver cyberjack_device = {
                .name =         "cyberjack",
        },
        .description =          "Reiner SCT Cyberjack USB card reader",
+       .usb_driver =           &cyberjack_driver,
        .id_table =             id_table,
        .num_interrupt_in =     1,
        .num_bulk_in =          1,
@@ -98,7 +99,7 @@ static struct usb_serial_driver cyberjack_device = {
        .open =                 cyberjack_open,
        .close =                cyberjack_close,
        .write =                cyberjack_write,
-       .write_room =   cyberjack_write_room,
+       .write_room =           cyberjack_write_room,
        .read_int_callback =    cyberjack_read_int_callback,
        .read_bulk_callback =   cyberjack_read_bulk_callback,
        .write_bulk_callback =  cyberjack_write_bulk_callback,
index 6bc1f40..57b8e27 100644 (file)
@@ -193,6 +193,7 @@ static struct usb_serial_driver cypress_earthmate_device = {
                .name =                 "earthmate",
        },
        .description =                  "DeLorme Earthmate USB",
+       .usb_driver =                   &cypress_driver,
        .id_table =                     id_table_earthmate,
        .num_interrupt_in =             1,
        .num_interrupt_out =            1,
@@ -222,6 +223,7 @@ static struct usb_serial_driver cypress_hidcom_device = {
                .name =                 "cyphidcom",
        },
        .description =                  "HID->COM RS232 Adapter",
+       .usb_driver =                   &cypress_driver,
        .id_table =                     id_table_cyphidcomrs232,
        .num_interrupt_in =             1,
        .num_interrupt_out =            1,
@@ -251,6 +253,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {
                 .name =                        "nokiaca42v2",
        },
        .description =                  "Nokia CA-42 V2 Adapter",
+       .usb_driver =                   &cypress_driver,
        .id_table =                     id_table_nokiaca42v2,
        .num_interrupt_in =             1,
        .num_interrupt_out =            1,
index efd9ce3..0b0fb51 100644 (file)
@@ -509,6 +509,7 @@ static struct usb_serial_driver digi_acceleport_2_device = {
                .name =                 "digi_2",
        },
        .description =                  "Digi 2 port USB adapter",
+       .usb_driver =                   &digi_driver,
        .id_table =                     id_table_2,
        .num_interrupt_in =             0,
        .num_bulk_in =                  4,
@@ -538,6 +539,7 @@ static struct usb_serial_driver digi_acceleport_4_device = {
                .name =                 "digi_4",
        },
        .description =                  "Digi 4 port USB adapter",
+       .usb_driver =                   &digi_driver,
        .id_table =                     id_table_4,
        .num_interrupt_in =             0,
        .num_bulk_in =                  5,
index 92beeb1..4703c8f 100644 (file)
@@ -117,6 +117,7 @@ static struct usb_serial_driver empeg_device = {
                .name =         "empeg",
        },
        .id_table =             id_table,
+       .usb_driver =           &empeg_driver,
        .num_interrupt_in =     0,
        .num_bulk_in =          1,
        .num_bulk_out =         1,
index 6986e75..4695952 100644 (file)
@@ -464,7 +464,6 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
        { USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
-       { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
        { USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
@@ -615,6 +614,7 @@ static struct usb_serial_driver ftdi_sio_device = {
                .name =         "ftdi_sio",
        },
        .description =          "FTDI USB Serial Device",
+       .usb_driver =           &ftdi_driver ,
        .id_table =             id_table_combined,
        .num_interrupt_in =     0,
        .num_bulk_in =          1,
index 40dd394..7eff1c0 100644 (file)
  * USB-TTY activ, USB-TTY passiv.  Some PIDs are used by several devices
  * and I'm not entirely sure which are used by which.
  */
-#define FTDI_4N_GALAXY_DE_0_PID        0x8372
 #define FTDI_4N_GALAXY_DE_1_PID        0xF3C0
 #define FTDI_4N_GALAXY_DE_2_PID        0xF3C1
 
index 2bebd63..4092f6d 100644 (file)
@@ -58,6 +58,7 @@ static struct usb_serial_driver funsoft_device = {
                .name =         "funsoft",
        },
        .id_table =             id_table,
+       .usb_driver =           &funsoft_driver,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
        .num_bulk_out =         NUM_DONT_CARE,
index 6530d39..74660a3 100644 (file)
@@ -1566,6 +1566,7 @@ static struct usb_serial_driver garmin_device = {
                .name        = "garmin_gps",
        },
        .description         = "Garmin GPS usb/tty",
+       .usb_driver          = &garmin_driver,
        .id_table            = id_table,
        .num_interrupt_in    = 1,
        .num_bulk_in         = 1,
index 3604293..601e064 100644 (file)
 #include <linux/usb/serial.h>
 #include <asm/uaccess.h>
 
+static int generic_probe(struct usb_interface *interface,
+                        const struct usb_device_id *id);
+
+
 static int debug;
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
@@ -34,6 +38,21 @@ MODULE_PARM_DESC(product, "User specified USB idProduct");
 
 static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
 
+/* we want to look at all devices, as the vendor/product id can change
+ * depending on the command line argument */
+static struct usb_device_id generic_serial_ids[] = {
+       {.driver_info = 42},
+       {}
+};
+
+static struct usb_driver generic_driver = {
+       .name =         "usbserial_generic",
+       .probe =        generic_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     generic_serial_ids,
+       .no_dynamic_id =        1,
+};
+
 /* All of the device info needed for the Generic Serial Converter */
 struct usb_serial_driver usb_serial_generic_device = {
        .driver = {
@@ -41,6 +60,7 @@ struct usb_serial_driver usb_serial_generic_device = {
                .name =         "generic",
        },
        .id_table =             generic_device_ids,
+       .usb_driver =           &generic_driver,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
        .num_bulk_out =         NUM_DONT_CARE,
@@ -48,13 +68,6 @@ struct usb_serial_driver usb_serial_generic_device = {
        .shutdown =             usb_serial_generic_shutdown,
 };
 
-/* we want to look at all devices, as the vendor/product id can change
- * depending on the command line argument */
-static struct usb_device_id generic_serial_ids[] = {
-       {.driver_info = 42},
-       {}
-};
-
 static int generic_probe(struct usb_interface *interface,
                               const struct usb_device_id *id)
 {
@@ -65,14 +78,6 @@ static int generic_probe(struct usb_interface *interface,
                return usb_serial_probe(interface, id);
        return -ENODEV;
 }
-
-static struct usb_driver generic_driver = {
-       .name =         "usbserial_generic",
-       .probe =        generic_probe,
-       .disconnect =   usb_serial_disconnect,
-       .id_table =     generic_serial_ids,
-       .no_dynamic_id =        1,
-};
 #endif
 
 int usb_serial_generic_register (int _debug)
index ebcac70..6c6ebae 100644 (file)
@@ -49,6 +49,7 @@ static struct usb_serial_driver hp49gp_device = {
                .name =         "hp4X",
        },
        .id_table =             id_table,
+       .usb_driver =           &hp49gp_driver,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
        .num_bulk_out =         NUM_DONT_CARE,
index f623d58..6a26a2e 100644 (file)
@@ -146,6 +146,8 @@ struct edgeport_serial {
        struct edge_manuf_descriptor    manuf_descriptor;       /* the manufacturer descriptor */
        struct edge_boot_descriptor     boot_descriptor;        /* the boot firmware descriptor */
        struct edgeport_product_info    product_info;           /* Product Info */
+       struct edge_compatibility_descriptor epic_descriptor;   /* Edgeport compatible descriptor */
+       int                     is_epic;                        /* flag if EPiC device or not */
 
        __u8                    interrupt_in_endpoint;          /* the interrupt endpoint handle */
        unsigned char *         interrupt_in_buffer;            /* the buffer we use for the interrupt endpoint */
@@ -240,14 +242,6 @@ static void edge_shutdown          (struct usb_serial *serial);
 
 #include "io_tables.h" /* all of the devices that this driver supports */
 
-static struct usb_driver io_driver = {
-       .name =         "io_edgeport",
-       .probe =        usb_serial_probe,
-       .disconnect =   usb_serial_disconnect,
-       .id_table =     id_table_combined,
-       .no_dynamic_id =        1,
-};
-
 /* function prototypes for all of our local functions */
 static void  process_rcvd_data         (struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength);
 static void process_rcvd_status                (struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3);
@@ -397,6 +391,7 @@ static int get_string (struct usb_device *dev, int Id, char *string, int buflen)
        unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2);
 
        kfree(pStringDesc);
+       dbg("%s - USB String %s", __FUNCTION__, string);
        return strlen(string);
 }
 
@@ -434,6 +429,34 @@ static int get_string_desc (struct usb_device *dev, int Id, struct usb_string_de
 }
 #endif
 
+static void dump_product_info(struct edgeport_product_info *product_info)
+{
+       // Dump Product Info structure
+       dbg("**Product Information:");
+       dbg("  ProductId             %x", product_info->ProductId );
+       dbg("  NumPorts              %d", product_info->NumPorts );
+       dbg("  ProdInfoVer           %d", product_info->ProdInfoVer );
+       dbg("  IsServer              %d", product_info->IsServer);
+       dbg("  IsRS232               %d", product_info->IsRS232 );
+       dbg("  IsRS422               %d", product_info->IsRS422 );
+       dbg("  IsRS485               %d", product_info->IsRS485 );
+       dbg("  RomSize               %d", product_info->RomSize );
+       dbg("  RamSize               %d", product_info->RamSize );
+       dbg("  CpuRev                %x", product_info->CpuRev  );
+       dbg("  BoardRev              %x", product_info->BoardRev);
+       dbg("  BootMajorVersion      %d.%d.%d", product_info->BootMajorVersion,
+           product_info->BootMinorVersion,
+           le16_to_cpu(product_info->BootBuildNumber));
+       dbg("  FirmwareMajorVersion  %d.%d.%d", product_info->FirmwareMajorVersion,
+           product_info->FirmwareMinorVersion,
+           le16_to_cpu(product_info->FirmwareBuildNumber));
+       dbg("  ManufactureDescDate   %d/%d/%d", product_info->ManufactureDescDate[0],
+           product_info->ManufactureDescDate[1],
+           product_info->ManufactureDescDate[2]+1900);
+       dbg("  iDownloadFile         0x%x", product_info->iDownloadFile);
+       dbg("  EpicVer               %d", product_info->EpicVer);
+}
+
 static void get_product_info(struct edgeport_serial *edge_serial)
 {
        struct edgeport_product_info *product_info = &edge_serial->product_info;
@@ -495,30 +518,60 @@ static void get_product_info(struct edgeport_serial *edge_serial)
                        break;
        }
 
-       // Dump Product Info structure
-       dbg("**Product Information:");
-       dbg("  ProductId             %x", product_info->ProductId );
-       dbg("  NumPorts              %d", product_info->NumPorts );
-       dbg("  ProdInfoVer           %d", product_info->ProdInfoVer );
-       dbg("  IsServer              %d", product_info->IsServer);
-       dbg("  IsRS232               %d", product_info->IsRS232 );
-       dbg("  IsRS422               %d", product_info->IsRS422 );
-       dbg("  IsRS485               %d", product_info->IsRS485 );
-       dbg("  RomSize               %d", product_info->RomSize );
-       dbg("  RamSize               %d", product_info->RamSize );
-       dbg("  CpuRev                %x", product_info->CpuRev  );
-       dbg("  BoardRev              %x", product_info->BoardRev);
-       dbg("  BootMajorVersion      %d.%d.%d", product_info->BootMajorVersion,
-           product_info->BootMinorVersion,
-           le16_to_cpu(product_info->BootBuildNumber));
-       dbg("  FirmwareMajorVersion  %d.%d.%d", product_info->FirmwareMajorVersion,
-           product_info->FirmwareMinorVersion,
-           le16_to_cpu(product_info->FirmwareBuildNumber));
-       dbg("  ManufactureDescDate   %d/%d/%d", product_info->ManufactureDescDate[0],
-           product_info->ManufactureDescDate[1],
-           product_info->ManufactureDescDate[2]+1900);
-       dbg("  iDownloadFile         0x%x",     product_info->iDownloadFile);
+       dump_product_info(product_info);
+}
 
+static int get_epic_descriptor(struct edgeport_serial *ep)
+{
+       int result;
+       struct usb_serial *serial = ep->serial;
+       struct edgeport_product_info *product_info = &ep->product_info;
+       struct edge_compatibility_descriptor *epic = &ep->epic_descriptor;
+       struct edge_compatibility_bits *bits;
+
+       ep->is_epic = 0;
+       result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+                                USB_REQUEST_ION_GET_EPIC_DESC,
+                                0xC0, 0x00, 0x00,
+                                &ep->epic_descriptor,
+                                sizeof(struct edge_compatibility_descriptor),
+                                300);
+
+       dbg("%s result = %d", __FUNCTION__, result);
+
+       if (result > 0) {
+               ep->is_epic = 1;
+               memset(product_info, 0, sizeof(struct edgeport_product_info));
+
+               product_info->NumPorts                  = epic->NumPorts;
+               product_info->ProdInfoVer               = 0;
+               product_info->FirmwareMajorVersion      = epic->MajorVersion;
+               product_info->FirmwareMinorVersion      = epic->MinorVersion;
+               product_info->FirmwareBuildNumber       = epic->BuildNumber;
+               product_info->iDownloadFile             = epic->iDownloadFile;
+               product_info->EpicVer                   = epic->EpicVer;
+               product_info->Epic                      = epic->Supports;
+               product_info->ProductId                 = ION_DEVICE_ID_EDGEPORT_COMPATIBLE;
+               dump_product_info(product_info);
+
+               bits = &ep->epic_descriptor.Supports;
+               dbg("**EPIC descriptor:");
+               dbg("  VendEnableSuspend: %s", bits->VendEnableSuspend  ? "TRUE": "FALSE");
+               dbg("  IOSPOpen         : %s", bits->IOSPOpen           ? "TRUE": "FALSE" );
+               dbg("  IOSPClose        : %s", bits->IOSPClose          ? "TRUE": "FALSE" );
+               dbg("  IOSPChase        : %s", bits->IOSPChase          ? "TRUE": "FALSE" );
+               dbg("  IOSPSetRxFlow    : %s", bits->IOSPSetRxFlow      ? "TRUE": "FALSE" );
+               dbg("  IOSPSetTxFlow    : %s", bits->IOSPSetTxFlow      ? "TRUE": "FALSE" );
+               dbg("  IOSPSetXChar     : %s", bits->IOSPSetXChar       ? "TRUE": "FALSE" );
+               dbg("  IOSPRxCheck      : %s", bits->IOSPRxCheck        ? "TRUE": "FALSE" );
+               dbg("  IOSPSetClrBreak  : %s", bits->IOSPSetClrBreak    ? "TRUE": "FALSE" );
+               dbg("  IOSPWriteMCR     : %s", bits->IOSPWriteMCR       ? "TRUE": "FALSE" );
+               dbg("  IOSPWriteLCR     : %s", bits->IOSPWriteLCR       ? "TRUE": "FALSE" );
+               dbg("  IOSPSetBaudRate  : %s", bits->IOSPSetBaudRate    ? "TRUE": "FALSE" );
+               dbg("  TrueEdgeport     : %s", bits->TrueEdgeport       ? "TRUE": "FALSE" );
+       }
+
+       return result;
 }
 
 
@@ -1017,21 +1070,29 @@ static void edge_close (struct usb_serial_port *port, struct file * filp)
 
        edge_port->closePending = TRUE;
 
-       /* flush and chase */
-       edge_port->chaseResponsePending = TRUE;
-
-       dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
-       status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
-       if (status == 0) {
-               // block until chase finished
-               block_until_chase_response(edge_port);
-       } else {
-               edge_port->chaseResponsePending = FALSE;
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+               /* flush and chase */
+               edge_port->chaseResponsePending = TRUE;
+
+               dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+               status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+               if (status == 0) {
+                       // block until chase finished
+                       block_until_chase_response(edge_port);
+               } else {
+                       edge_port->chaseResponsePending = FALSE;
+               }
        }
 
-       /* close the port */
-       dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
-       send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (edge_serial->epic_descriptor.Supports.IOSPClose))) {
+              /* close the port */
+               dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
+               send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+       }
 
        //port->close = TRUE;
        edge_port->closePending = FALSE;
@@ -1694,29 +1755,38 @@ static int edge_ioctl (struct usb_serial_port *port, struct file *file, unsigned
 static void edge_break (struct usb_serial_port *port, int break_state)
 {
        struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+       struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial);
        int status;
 
-       /* flush and chase */
-       edge_port->chaseResponsePending = TRUE;
-
-       dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
-       status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
-       if (status == 0) {
-               // block until chase finished
-               block_until_chase_response(edge_port);
-       } else {
-               edge_port->chaseResponsePending = FALSE;
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+               /* flush and chase */
+               edge_port->chaseResponsePending = TRUE;
+
+               dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+               status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+               if (status == 0) {
+                       // block until chase finished
+                       block_until_chase_response(edge_port);
+               } else {
+                       edge_port->chaseResponsePending = FALSE;
+               }
        }
 
-       if (break_state == -1) {
-               dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
-               status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
-       } else {
-               dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
-               status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
-       }
-       if (status) {
-               dbg("%s - error sending break set/clear command.", __FUNCTION__);
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) {
+               if (break_state == -1) {
+                       dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
+                       status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
+               } else {
+                       dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
+                       status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
+               }
+               if (status) {
+                       dbg("%s - error sending break set/clear command.", __FUNCTION__);
+               }
        }
 
        return;
@@ -2288,6 +2358,7 @@ static int write_cmd_usb (struct edgeport_port *edge_port, unsigned char *buffer
  *****************************************************************************/
 static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate)
 {
+       struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
        unsigned char *cmdBuffer;
        unsigned char *currCmd;
        int cmdLen = 0;
@@ -2295,6 +2366,14 @@ static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRa
        int status;
        unsigned char number = edge_port->port->number - edge_port->port->serial->minor;
 
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate))) {
+               dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d",
+                   edge_port->port->number, baudRate);
+               return 0;
+       }
+
        dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate);
 
        status = calc_baud_rate_divisor (baudRate, &divisor);
@@ -2374,6 +2453,7 @@ static int calc_baud_rate_divisor (int baudrate, int *divisor)
  *****************************************************************************/
 static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue)
 {
+       struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
        unsigned char *cmdBuffer;
        unsigned char *currCmd;
        unsigned long cmdLen = 0;
@@ -2381,6 +2461,22 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
 
        dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue);
 
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) &&
+            (regNum == MCR))) {
+               dbg("SendCmdWriteUartReg - Not writting to MCR Register");
+               return 0;
+       }
+
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) &&
+            (regNum == LCR))) {
+               dbg ("SendCmdWriteUartReg - Not writting to LCR Register");
+               return 0;
+       }
+
        // Alloc memory for the string of commands.
        cmdBuffer = kmalloc (0x10, GFP_ATOMIC);
        if (cmdBuffer == NULL ) {
@@ -2414,6 +2510,7 @@ static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 r
 #endif
 static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios)
 {
+       struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
        struct tty_struct *tty;
        int baud;
        unsigned cflag;
@@ -2494,8 +2591,12 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
                unsigned char stop_char  = STOP_CHAR(tty);
                unsigned char start_char = START_CHAR(tty);
 
-               send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
-               send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+               if ((!edge_serial->is_epic) ||
+                   ((edge_serial->is_epic) &&
+                    (edge_serial->epic_descriptor.Supports.IOSPSetXChar))) {
+                       send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
+                       send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+               }
 
                /* if we are implementing INBOUND XON/XOFF */
                if (I_IXOFF(tty)) {
@@ -2515,8 +2616,14 @@ static void change_port_settings (struct edgeport_port *edge_port, struct ktermi
        }
 
        /* Set flow control to the configured value */
-       send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
-       send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (edge_serial->epic_descriptor.Supports.IOSPSetRxFlow)))
+               send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
+       if ((!edge_serial->is_epic) ||
+           ((edge_serial->is_epic) &&
+            (edge_serial->epic_descriptor.Supports.IOSPSetTxFlow)))
+               send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
 
 
        edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
@@ -2728,6 +2835,13 @@ static int edge_startup (struct usb_serial *serial)
        struct edgeport_port *edge_port;
        struct usb_device *dev;
        int i, j;
+       int response;
+       int interrupt_in_found;
+       int bulk_in_found;
+       int bulk_out_found;
+       static __u32 descriptor[3] = {  EDGE_COMPATIBILITY_MASK0,
+                                       EDGE_COMPATIBILITY_MASK1,
+                                       EDGE_COMPATIBILITY_MASK2 };
 
        dev = serial->dev;
 
@@ -2750,38 +2864,50 @@ static int edge_startup (struct usb_serial *serial)
 
        dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
 
-       /* get the manufacturing descriptor for this device */
-       get_manufacturing_desc (edge_serial);
+       /* Read the epic descriptor */
+       if (get_epic_descriptor(edge_serial) <= 0) {
+               /* memcpy descriptor to Supports structures */
+               memcpy(&edge_serial->epic_descriptor.Supports, descriptor,
+                      sizeof(struct edge_compatibility_bits));
+
+               /* get the manufacturing descriptor for this device */
+               get_manufacturing_desc (edge_serial);
 
-       /* get the boot descriptor */
-       get_boot_desc (edge_serial);
+               /* get the boot descriptor */
+               get_boot_desc (edge_serial);
 
-       get_product_info(edge_serial);
+               get_product_info(edge_serial);
+       }
 
        /* set the number of ports from the manufacturing description */
        /* serial->num_ports = serial->product_info.NumPorts; */
-       if (edge_serial->product_info.NumPorts != serial->num_ports) {
-               warn("%s - Device Reported %d serial ports vs core "
-                    "thinking we have %d ports, email greg@kroah.com this info.",
-                    __FUNCTION__, edge_serial->product_info.NumPorts, 
-                    serial->num_ports);
+       if ((!edge_serial->is_epic) &&
+           (edge_serial->product_info.NumPorts != serial->num_ports)) {
+               dev_warn(&serial->dev->dev, "Device Reported %d serial ports "
+                        "vs. core thinking we have %d ports, email "
+                        "greg@kroah.com this information.",
+                        edge_serial->product_info.NumPorts,
+                        serial->num_ports);
        }
 
        dbg("%s - time 1 %ld", __FUNCTION__, jiffies);
 
-       /* now load the application firmware into this device */
-       load_application_firmware (edge_serial);
+       /* If not an EPiC device */
+       if (!edge_serial->is_epic) {
+               /* now load the application firmware into this device */
+               load_application_firmware (edge_serial);
 
-       dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
+               dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
 
-       /* Check current Edgeport EEPROM and update if necessary */
-       update_edgeport_E2PROM (edge_serial);
-       
-       dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+               /* Check current Edgeport EEPROM and update if necessary */
+               update_edgeport_E2PROM (edge_serial);
 
-       /* set the configuration to use #1 */
-//     dbg("set_configuration 1");
-//     usb_set_configuration (dev, 1);
+               dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+
+               /* set the configuration to use #1 */
+//             dbg("set_configuration 1");
+//             usb_set_configuration (dev, 1);
+       }
 
        /* we set up the pointers to the endpoints in the edge_open function, 
         * as the structures aren't created yet. */
@@ -2804,8 +2930,101 @@ static int edge_startup (struct usb_serial *serial)
                edge_port->port = serial->port[i];
                usb_set_serial_port_data(serial->port[i], edge_port);
        }
-       
-       return 0;
+
+       response = 0;
+
+       if (edge_serial->is_epic) {
+               /* EPIC thing, set up our interrupt polling now and our read urb, so
+                * that the device knows it really is connected. */
+               interrupt_in_found = bulk_in_found = bulk_out_found = FALSE;
+               for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) {
+                       struct usb_endpoint_descriptor *endpoint;
+                       int buffer_size;
+
+                       endpoint = &serial->interface->altsetting[0].endpoint[i].desc;
+                       buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+                       if ((!interrupt_in_found) &&
+                           (usb_endpoint_is_int_in(endpoint))) {
+                               /* we found a interrupt in endpoint */
+                               dbg("found interrupt in");
+
+                               /* not set up yet, so do it now */
+                               edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL);
+                               if (!edge_serial->interrupt_read_urb) {
+                                       err("out of memory");
+                                       return -ENOMEM;
+                               }
+                               edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+                               if (!edge_serial->interrupt_in_buffer) {
+                                       err("out of memory");
+                                       usb_free_urb(edge_serial->interrupt_read_urb);
+                                       return -ENOMEM;
+                               }
+                               edge_serial->interrupt_in_endpoint = endpoint->bEndpointAddress;
+
+                               /* set up our interrupt urb */
+                               usb_fill_int_urb(edge_serial->interrupt_read_urb,
+                                                dev,
+                                                usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+                                                edge_serial->interrupt_in_buffer,
+                                                buffer_size,
+                                                edge_interrupt_callback,
+                                                edge_serial,
+                                                endpoint->bInterval);
+
+                               interrupt_in_found = TRUE;
+                       }
+
+                       if ((!bulk_in_found) &&
+                           (usb_endpoint_is_bulk_in(endpoint))) {
+                               /* we found a bulk in endpoint */
+                               dbg("found bulk in");
+
+                               /* not set up yet, so do it now */
+                               edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+                               if (!edge_serial->read_urb) {
+                                       err("out of memory");
+                                       return -ENOMEM;
+                               }
+                               edge_serial->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+                               if (!edge_serial->bulk_in_buffer) {
+                                       err ("out of memory");
+                                       usb_free_urb(edge_serial->read_urb);
+                                       return -ENOMEM;
+                               }
+                               edge_serial->bulk_in_endpoint = endpoint->bEndpointAddress;
+
+                               /* set up our bulk in urb */
+                               usb_fill_bulk_urb(edge_serial->read_urb, dev,
+                                                 usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+                                                 edge_serial->bulk_in_buffer,
+                                                 endpoint->wMaxPacketSize,
+                                                 edge_bulk_in_callback,
+                                                 edge_serial);
+                               bulk_in_found = TRUE;
+                       }
+
+                       if ((!bulk_out_found) &&
+                           (usb_endpoint_is_bulk_out(endpoint))) {
+                               /* we found a bulk out endpoint */
+                               dbg("found bulk out");
+                               edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress;
+                               bulk_out_found = TRUE;
+                       }
+               }
+
+               if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) {
+                       err ("Error - the proper endpoints were not found!");
+                       return -ENODEV;
+               }
+
+               /* start interrupt read for this edgeport this interrupt will
+                * continue as long as the edgeport is connected */
+               response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL);
+               if (response)
+                       err("%s - Error %d submitting control urb", __FUNCTION__, response);
+       }
+       return response;
 }
 
 
@@ -2815,6 +3034,7 @@ static int edge_startup (struct usb_serial *serial)
  ****************************************************************************/
 static void edge_shutdown (struct usb_serial *serial)
 {
+       struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
        int i;
 
        dbg("%s", __FUNCTION__);
@@ -2824,7 +3044,18 @@ static void edge_shutdown (struct usb_serial *serial)
                kfree (usb_get_serial_port_data(serial->port[i]));
                usb_set_serial_port_data(serial->port[i],  NULL);
        }
-       kfree (usb_get_serial_data(serial));
+       /* free up our endpoint stuff */
+       if (edge_serial->is_epic) {
+               usb_unlink_urb(edge_serial->interrupt_read_urb);
+               usb_free_urb(edge_serial->interrupt_read_urb);
+               kfree(edge_serial->interrupt_in_buffer);
+
+               usb_unlink_urb(edge_serial->read_urb);
+               usb_free_urb(edge_serial->read_urb);
+               kfree(edge_serial->bulk_in_buffer);
+       }
+
+       kfree(edge_serial);
        usb_set_serial_data(serial, NULL);
 }
 
@@ -2846,6 +3077,9 @@ static int __init edgeport_init(void)
        retval = usb_serial_register(&edgeport_8port_device);
        if (retval)
                goto failed_8port_device_register;
+       retval = usb_serial_register(&epic_device);
+       if (retval)
+               goto failed_epic_device_register;
        retval = usb_register(&io_driver);
        if (retval) 
                goto failed_usb_register;
@@ -2853,6 +3087,8 @@ static int __init edgeport_init(void)
        return 0;
 
 failed_usb_register:
+       usb_serial_deregister(&epic_device);
+failed_epic_device_register:
        usb_serial_deregister(&edgeport_8port_device);
 failed_8port_device_register:
        usb_serial_deregister(&edgeport_4port_device);
@@ -2873,6 +3109,7 @@ static void __exit edgeport_exit (void)
        usb_serial_deregister (&edgeport_2port_device);
        usb_serial_deregister (&edgeport_4port_device);
        usb_serial_deregister (&edgeport_8port_device);
+       usb_serial_deregister (&epic_device);
 }
 
 module_init(edgeport_init);
index 123fa8a..29a913a 100644 (file)
@@ -111,10 +111,12 @@ struct edgeport_product_info {
        __le16  FirmwareBuildNumber;            /*                              zzzz (LE format) */
 
        __u8    ManufactureDescDate[3];         /* MM/DD/YY when descriptor template was compiled */
-       __u8    Unused1[1];                     /* Available */
+       __u8    HardwareType;
 
        __u8    iDownloadFile;                  /* What to download to EPiC device */
-       __u8    Unused2[2];                     /* Available */
+       __u8    EpicVer;                        /* What version of EPiC spec this device supports */
+
+       struct edge_compatibility_bits Epic;
 };
 
 /*
index fad561c..6d30087 100644 (file)
@@ -47,6 +47,18 @@ static struct usb_device_id edgeport_8port_id_table [] = {
        { }
 };
 
+static struct usb_device_id Epic_port_id_table [] = {
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+       { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+       { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+       { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
+       { }
+};
+
 /* Devices that this driver supports */
 static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) },
@@ -70,17 +82,34 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+       { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+       { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+       { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+       { USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
        { }                                                     /* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
+static struct usb_driver io_driver = {
+       .name =         "io_edgeport",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     id_table_combined,
+       .no_dynamic_id =        1,
+};
+
 static struct usb_serial_driver edgeport_2port_device = {
        .driver = {
                .owner          = THIS_MODULE,
                .name           = "edgeport_2",
        },
        .description            = "Edgeport 2 port adapter",
+       .usb_driver             = &io_driver,
        .id_table               = edgeport_2port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 1,
@@ -111,6 +140,7 @@ static struct usb_serial_driver edgeport_4port_device = {
                .name           = "edgeport_4",
        },
        .description            = "Edgeport 4 port adapter",
+       .usb_driver             = &io_driver,
        .id_table               = edgeport_4port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 1,
@@ -141,6 +171,7 @@ static struct usb_serial_driver edgeport_8port_device = {
                .name           = "edgeport_8",
        },
        .description            = "Edgeport 8 port adapter",
+       .usb_driver             = &io_driver,
        .id_table               = edgeport_8port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 1,
@@ -165,5 +196,35 @@ static struct usb_serial_driver edgeport_8port_device = {
        .write_bulk_callback    = edge_bulk_out_data_callback,
 };
 
+static struct usb_serial_driver epic_device = {
+       .driver = {
+               .owner          = THIS_MODULE,
+               .name           = "epic",
+       },
+       .description            = "EPiC device",
+       .id_table               = Epic_port_id_table,
+       .num_interrupt_in       = 1,
+       .num_bulk_in            = 1,
+       .num_bulk_out           = 1,
+       .num_ports              = 1,
+       .open                   = edge_open,
+       .close                  = edge_close,
+       .throttle               = edge_throttle,
+       .unthrottle             = edge_unthrottle,
+       .attach                 = edge_startup,
+       .shutdown               = edge_shutdown,
+       .ioctl                  = edge_ioctl,
+       .set_termios            = edge_set_termios,
+       .tiocmget               = edge_tiocmget,
+       .tiocmset               = edge_tiocmset,
+       .write                  = edge_write,
+       .write_room             = edge_write_room,
+       .chars_in_buffer        = edge_chars_in_buffer,
+       .break_ctl              = edge_break,
+       .read_int_callback      = edge_interrupt_callback,
+       .read_bulk_callback     = edge_bulk_in_callback,
+       .write_bulk_callback    = edge_bulk_out_data_callback,
+};
+
 #endif
 
index 980285c..544098d 100644 (file)
@@ -2979,6 +2979,7 @@ static struct usb_serial_driver edgeport_1port_device = {
                .name           = "edgeport_ti_1",
        },
        .description            = "Edgeport TI 1 port adapter",
+       .usb_driver             = &io_driver,
        .id_table               = edgeport_1port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 1,
@@ -3009,6 +3010,7 @@ static struct usb_serial_driver edgeport_2port_device = {
                .name           = "edgeport_ti_2",
        },
        .description            = "Edgeport TI 2 port adapter",
+       .usb_driver             = &io_driver,
        .id_table               = edgeport_2port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 2,
index f1804fd..e57fa11 100644 (file)
@@ -30,6 +30,7 @@
 
 #define        USB_VENDOR_ID_ION       0x1608          // Our VID
 #define        USB_VENDOR_ID_TI        0x0451          // TI VID
+#define USB_VENDOR_ID_AXIOHM   0x05D9          /* Axiohm VID */
 
 //
 // Definitions of USB product IDs (PID)
@@ -334,6 +335,10 @@ struct edge_compatibility_bits
 
 };
 
+#define EDGE_COMPATIBILITY_MASK0       0x0001
+#define EDGE_COMPATIBILITY_MASK1       0x3FFF
+#define EDGE_COMPATIBILITY_MASK2       0x0001
+
 struct edge_compatibility_descriptor
 {
        __u8    Length;                         // Descriptor Length (per USB spec)
index 42f757a..a408184 100644 (file)
@@ -563,6 +563,7 @@ static struct usb_serial_driver ipaq_device = {
                .name =         "ipaq",
        },
        .description =          "PocketPC PDA",
+       .usb_driver =           &ipaq_driver,
        .id_table =             ipaq_id_table,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          1,
index d3b9a35..1bc5860 100644 (file)
@@ -442,6 +442,7 @@ static struct usb_serial_driver ipw_device = {
                .name =         "ipw",
        },
        .description =          "IPWireless converter",
+       .usb_driver =           &usb_ipw_driver,
        .id_table =             usb_ipw_ids,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          1,
index 8fdf486..9d847f6 100644 (file)
@@ -138,6 +138,7 @@ static struct usb_serial_driver ir_device = {
                .name =         "ir-usb",
        },
        .description =          "IR Dongle",
+       .usb_driver =           &ir_driver,
        .id_table =             id_table,
        .num_interrupt_in =     1,
        .num_bulk_in =          1,
index 9d2fdfd..e6966f1 100644 (file)
@@ -1275,11 +1275,31 @@ static int keyspan_fake_startup (struct usb_serial *serial)
 }
 
 /* Helper functions used by keyspan_setup_urbs */
+static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
+                                                    int endpoint)
+{
+       struct usb_host_interface *iface_desc;
+       struct usb_endpoint_descriptor *ep;
+       int i;
+
+       iface_desc = serial->interface->cur_altsetting;
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+               ep = &iface_desc->endpoint[i].desc;
+               if (ep->bEndpointAddress == endpoint)
+                       return ep;
+       }
+       dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
+                "endpoint %x\n", endpoint);
+       return NULL;
+}
+
 static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
                                      int dir, void *ctx, char *buf, int len,
                                      void (*callback)(struct urb *))
 {
        struct urb *urb;
+       struct usb_endpoint_descriptor const *ep_desc;
+       char const *ep_type_name;
 
        if (endpoint == -1)
                return NULL;            /* endpoint not needed */
@@ -1291,11 +1311,32 @@ static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
                return NULL;
        }
 
-               /* Fill URB using supplied data. */
-       usb_fill_bulk_urb(urb, serial->dev,
-                     usb_sndbulkpipe(serial->dev, endpoint) | dir,
-                     buf, len, callback, ctx);
+       ep_desc = find_ep(serial, endpoint);
+       if (!ep_desc) {
+               /* leak the urb, something's wrong and the callers don't care */
+               return urb;
+       }
+       if (usb_endpoint_xfer_int(ep_desc)) {
+               ep_type_name = "INT";
+               usb_fill_int_urb(urb, serial->dev,
+                                usb_sndintpipe(serial->dev, endpoint) | dir,
+                                buf, len, callback, ctx,
+                                ep_desc->bInterval);
+       } else if (usb_endpoint_xfer_bulk(ep_desc)) {
+               ep_type_name = "BULK";
+               usb_fill_bulk_urb(urb, serial->dev,
+                                 usb_sndbulkpipe(serial->dev, endpoint) | dir,
+                                 buf, len, callback, ctx);
+       } else {
+               dev_warn(&serial->interface->dev,
+                        "unsupported endpoint type %x\n",
+                        ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+               usb_free_urb(urb);
+               return NULL;
+       }
 
+       dbg("%s - using urb %p for %s endpoint %x",
+           __func__, urb, ep_type_name, endpoint);
        return urb;
 }
 
index 6413d73..c6830cb 100644 (file)
@@ -229,7 +229,6 @@ struct ezusb_hex_record {
 #define        keyspan_usa28_product_id                0x010f
 #define        keyspan_usa28x_product_id               0x0110
 #define        keyspan_usa28xa_product_id              0x0115
-#define        keyspan_usa28xb_product_id              0x0110
 #define        keyspan_usa49w_product_id               0x010a
 #define        keyspan_usa49wlc_product_id             0x012a
 
@@ -511,7 +510,6 @@ static struct usb_device_id keyspan_ids_combined[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
-       { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
        { } /* Terminating entry */
@@ -559,7 +557,6 @@ static struct usb_device_id keyspan_2port_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
-       { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
        { } /* Terminating entry */
 };
 
@@ -576,6 +573,7 @@ static struct usb_serial_driver keyspan_pre_device = {
                .name           = "keyspan_no_firm",
        },
        .description            = "Keyspan - (without firmware)",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_pre_ids,
        .num_interrupt_in       = NUM_DONT_CARE,
        .num_bulk_in            = NUM_DONT_CARE,
@@ -590,6 +588,7 @@ static struct usb_serial_driver keyspan_1port_device = {
                .name           = "keyspan_1",
        },
        .description            = "Keyspan 1 port adapter",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_1port_ids,
        .num_interrupt_in       = NUM_DONT_CARE,
        .num_bulk_in            = NUM_DONT_CARE,
@@ -617,6 +616,7 @@ static struct usb_serial_driver keyspan_2port_device = {
                .name           = "keyspan_2",
        },
        .description            = "Keyspan 2 port adapter",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_2port_ids,
        .num_interrupt_in       = NUM_DONT_CARE,
        .num_bulk_in            = NUM_DONT_CARE,
@@ -644,6 +644,7 @@ static struct usb_serial_driver keyspan_4port_device = {
                .name           = "keyspan_4",
        },
        .description            = "Keyspan 4 port adapter",
+       .usb_driver             = &keyspan_driver,
        .id_table               = keyspan_4port_ids,
        .num_interrupt_in       = NUM_DONT_CARE,
        .num_bulk_in            = 5,
index 126b970..da514cb 100644 (file)
@@ -793,6 +793,7 @@ static struct usb_serial_driver keyspan_pda_fake_device = {
                .name =         "keyspan_pda_pre",
        },
        .description =          "Keyspan PDA - (prerenumeration)",
+       .usb_driver =           &keyspan_pda_driver,
        .id_table =             id_table_fake,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
@@ -809,6 +810,7 @@ static struct usb_serial_driver xircom_pgs_fake_device = {
                .name =         "xircom_no_firm",
        },
        .description =          "Xircom / Entregra PGS - (prerenumeration)",
+       .usb_driver =           &keyspan_pda_driver,
        .id_table =             id_table_fake_xircom,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
@@ -824,6 +826,7 @@ static struct usb_serial_driver keyspan_pda_device = {
                .name =         "keyspan_pda",
        },
        .description =          "Keyspan PDA",
+       .usb_driver =           &keyspan_pda_driver,
        .id_table =             id_table_std,
        .num_interrupt_in =     1,
        .num_bulk_in =          0,
index 5c4b06a..b2097c4 100644 (file)
@@ -124,6 +124,7 @@ static struct usb_serial_driver kl5kusb105d_device = {
                .name =         "kl5kusb105d",
        },
        .description =       "KL5KUSB105D / PalmConnect",
+       .usb_driver =        &kl5kusb105d_driver,
        .id_table =          id_table,
        .num_interrupt_in =  1,
        .num_bulk_in =       1,
index 62bea0c..0683b51 100644 (file)
@@ -110,6 +110,7 @@ static struct usb_serial_driver kobil_device = {
                .name =         "kobil",
        },
        .description =          "KOBIL USB smart card terminal",
+       .usb_driver =           &kobil_driver,
        .id_table =             id_table,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          0,
index 38b1d17..4cd839b 100644 (file)
@@ -137,6 +137,7 @@ static struct usb_serial_driver mct_u232_device = {
                .name =         "mct_u232",
        },
        .description =       "MCT U232",
+       .usb_driver =        &mct_u232_driver,
        .id_table =          id_table_combined,
        .num_interrupt_in =  2,
        .num_bulk_in =       0,
index e55f4ed..6109c67 100644 (file)
@@ -1605,12 +1605,21 @@ static void mos7720_shutdown(struct usb_serial *serial)
        usb_set_serial_data(serial, NULL);
 }
 
+static struct usb_driver usb_driver = {
+       .name =         "moschip7720",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     moschip_port_id_table,
+       .no_dynamic_id =        1,
+};
+
 static struct usb_serial_driver moschip7720_2port_driver = {
        .driver = {
                .owner =        THIS_MODULE,
                .name =         "moschip7720",
        },
        .description            = "Moschip 2 port adapter",
+       .usb_driver             = &usb_driver,
        .id_table               = moschip_port_id_table,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 2,
@@ -1631,13 +1640,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
        .read_bulk_callback     = mos7720_bulk_in_callback,
 };
 
-static struct usb_driver usb_driver = {
-       .name =         "moschip7720",
-       .probe =        usb_serial_probe,
-       .disconnect =   usb_serial_disconnect,
-       .id_table =     moschip_port_id_table,
-};
-
 static int __init moschip7720_init(void)
 {
        int retval;
index 83f6614..b2264a8 100644 (file)
@@ -2834,12 +2834,21 @@ static void mos7840_shutdown(struct usb_serial *serial)
 
 }
 
+static struct usb_driver io_driver = {
+       .name = "mos7840",
+       .probe = usb_serial_probe,
+       .disconnect = usb_serial_disconnect,
+       .id_table = moschip_id_table_combined,
+       .no_dynamic_id = 1,
+};
+
 static struct usb_serial_driver moschip7840_4port_device = {
        .driver = {
                   .owner = THIS_MODULE,
                   .name = "mos7840",
                   },
        .description = DRIVER_DESC,
+       .usb_driver = &io_driver,
        .id_table = moschip_port_id_table,
        .num_interrupt_in = 1,  //NUM_DONT_CARE,//1,
 #ifdef check
@@ -2869,13 +2878,6 @@ static struct usb_serial_driver moschip7840_4port_device = {
        .read_int_callback = mos7840_interrupt_callback,
 };
 
-static struct usb_driver io_driver = {
-       .name = "mos7840",
-       .probe = usb_serial_probe,
-       .disconnect = usb_serial_disconnect,
-       .id_table = moschip_id_table_combined,
-};
-
 /****************************************************************************
  * moschip7840_init
  *     This is called by the module subsystem, or on startup to initialize us
index 054abee..9070111 100644 (file)
@@ -119,6 +119,7 @@ static struct usb_serial_driver navman_device = {
                .name =         "navman",
        },
        .id_table =             id_table,
+       .usb_driver =           &navman_driver,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
        .num_bulk_out =         NUM_DONT_CARE,
index bc91d3b..0216ac1 100644 (file)
@@ -93,6 +93,7 @@ static struct usb_serial_driver zyxel_omninet_device = {
                .name =         "omninet",
        },
        .description =          "ZyXEL - omni.net lcd plus usb",
+       .usb_driver =           &omninet_driver,
        .id_table =             id_table,
        .num_interrupt_in =     1,
        .num_bulk_in =          1,
index 0fed43a..ced9f32 100644 (file)
@@ -135,6 +135,7 @@ static struct usb_serial_driver option_1port_device = {
                .name =         "option1",
        },
        .description       = "GSM modem (1-port)",
+       .usb_driver        = &option_driver,
        .id_table          = option_ids1,
        .num_interrupt_in  = NUM_DONT_CARE,
        .num_bulk_in       = NUM_DONT_CARE,
index 5dc2ac9..6c083d4 100644 (file)
@@ -1118,6 +1118,7 @@ static struct usb_serial_driver pl2303_device = {
                .name =         "pl2303",
        },
        .id_table =             id_table,
+       .usb_driver =           &pl2303_driver,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          1,
        .num_bulk_out =         1,
index 30b7ebc..5a03a3f 100644 (file)
@@ -402,6 +402,7 @@ static struct usb_serial_driver safe_device = {
                .name =         "safe_serial",
        },
        .id_table =             id_table,
+       .usb_driver =           &safe_driver,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
        .num_bulk_out =         NUM_DONT_CARE,
index 6d8e91e..ecedd83 100644 (file)
   Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
   Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
 
-  History:
 */
 
-#define DRIVER_VERSION "v.1.0.5"
+#define DRIVER_VERSION "v.1.0.6"
 #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
 #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
 
 
 static struct usb_device_id id_table [] = {
+       { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
-       { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
-       { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
        { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
-       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
        { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
        { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
 
@@ -55,14 +55,15 @@ static struct usb_device_id id_table_1port [] = {
 };
 
 static struct usb_device_id id_table_3port [] = {
+       { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0018) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
        { USB_DEVICE(0x1199, 0x0020) }, /* Sierra Wireless MC5725 */
-       { USB_DEVICE(0x1199, 0x0017) }, /* Sierra Wireless EM5625 */
        { USB_DEVICE(0x1199, 0x0019) }, /* Sierra Wireless AirCard 595 */
-       { USB_DEVICE(0x1199, 0x0218) }, /* Sierra Wireless MC5720 */
+       { USB_DEVICE(0x1199, 0x0021) }, /* Sierra Wireless AirCard 597E */
        { USB_DEVICE(0x1199, 0x6802) }, /* Sierra Wireless MC8755 */
+       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 */
        { USB_DEVICE(0x1199, 0x6803) }, /* Sierra Wireless MC8765 */
-       { USB_DEVICE(0x1199, 0x6804) }, /* Sierra Wireless MC8755 for Europe */
        { USB_DEVICE(0x1199, 0x6812) }, /* Sierra Wireless MC8775 */
        { USB_DEVICE(0x1199, 0x6820) }, /* Sierra Wireless AirCard 875 */
        { }
@@ -81,7 +82,7 @@ static int debug;
 
 /* per port private data */
 #define N_IN_URB       4
-#define N_OUT_URB      1
+#define N_OUT_URB      4
 #define IN_BUFLEN      4096
 #define OUT_BUFLEN     128
 
@@ -396,6 +397,8 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
        struct usb_serial *serial = port->serial;
        int i, err;
        struct urb *urb;
+       int result;
+       __u16 set_mode_dzero = 0x0000;
 
        portdata = usb_get_serial_port_data(port);
 
@@ -442,6 +445,12 @@ static int sierra_open(struct usb_serial_port *port, struct file *filp)
 
        port->tty->low_latency = 1;
 
+       /* set mode to D0 */
+       result = usb_control_msg(serial->dev,
+                                usb_rcvctrlpipe(serial->dev, 0),
+                                0x00, 0x40, set_mode_dzero, 0, NULL,
+                                0, USB_CTRL_SET_TIMEOUT);
+
        sierra_send_setup(port);
 
        return (0);
@@ -614,6 +623,7 @@ static struct usb_serial_driver sierra_1port_device = {
        },
        .description       = "Sierra USB modem (1 port)",
        .id_table          = id_table_1port,
+       .usb_driver        = &sierra_driver,
        .num_interrupt_in  = NUM_DONT_CARE,
        .num_bulk_in       = 1,
        .num_bulk_out      = 1,
@@ -642,6 +652,7 @@ static struct usb_serial_driver sierra_3port_device = {
        },
        .description       = "Sierra USB modem (3 port)",
        .id_table          = id_table_3port,
+       .usb_driver        = &sierra_driver,
        .num_interrupt_in  = NUM_DONT_CARE,
        .num_bulk_in       = 3,
        .num_bulk_out      = 3,
index 8318900..4203e2b 100644 (file)
@@ -262,6 +262,7 @@ static struct usb_serial_driver ti_1port_device = {
                .name           = "ti_usb_3410_5052_1",
        },
        .description            = "TI USB 3410 1 port adapter",
+       .usb_driver             = &ti_usb_driver,
        .id_table               = ti_id_table_3410,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 1,
@@ -292,6 +293,7 @@ static struct usb_serial_driver ti_2port_device = {
                .name           = "ti_usb_3410_5052_2",
        },
        .description            = "TI USB 5052 2 port adapter",
+       .usb_driver             = &ti_usb_driver,
        .id_table               = ti_id_table_5052,
        .num_interrupt_in       = 1,
        .num_bulk_in            = 2,
index 716f680..6bf22a2 100644 (file)
@@ -59,14 +59,19 @@ static struct usb_driver usb_serial_driver = {
 
 static int debug;
 static struct usb_serial *serial_table[SERIAL_TTY_MINORS];     /* initially all NULL */
+static spinlock_t table_lock;
 static LIST_HEAD(usb_serial_driver_list);
 
 struct usb_serial *usb_serial_get_by_index(unsigned index)
 {
-       struct usb_serial *serial = serial_table[index];
+       struct usb_serial *serial;
+
+       spin_lock(&table_lock);
+       serial = serial_table[index];
 
        if (serial)
                kref_get(&serial->kref);
+       spin_unlock(&table_lock);
        return serial;
 }
 
@@ -78,6 +83,7 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
        dbg("%s %d", __FUNCTION__, num_ports);
 
        *minor = 0;
+       spin_lock(&table_lock);
        for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
                if (serial_table[i])
                        continue;
@@ -96,8 +102,10 @@ static struct usb_serial *get_free_serial (struct usb_serial *serial, int num_po
                dbg("%s - minor base = %d", __FUNCTION__, *minor);
                for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
                        serial_table[i] = serial;
+               spin_unlock(&table_lock);
                return serial;
        }
+       spin_unlock(&table_lock);
        return NULL;
 }
 
@@ -110,9 +118,11 @@ static void return_serial(struct usb_serial *serial)
        if (serial == NULL)
                return;
 
+       spin_lock(&table_lock);
        for (i = 0; i < serial->num_ports; ++i) {
                serial_table[serial->minor + i] = NULL;
        }
+       spin_unlock(&table_lock);
 }
 
 static void destroy_serial(struct kref *kref)
@@ -271,7 +281,7 @@ static void serial_close(struct tty_struct *tty, struct file * filp)
 static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
 {
        struct usb_serial_port *port = tty->driver_data;
-       int retval = -EINVAL;
+       int retval = -ENODEV;
 
        if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
                goto exit;
@@ -279,6 +289,7 @@ static int serial_write (struct tty_struct * tty, const unsigned char *buf, int
        dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
 
        if (!port->open_count) {
+               retval = -EINVAL;
                dbg("%s - port not opened", __FUNCTION__);
                goto exit;
        }
@@ -559,15 +570,20 @@ static void port_release(struct device *dev)
        port_free(port);
 }
 
-static void port_free(struct usb_serial_port *port)
+static void kill_traffic(struct usb_serial_port *port)
 {
        usb_kill_urb(port->read_urb);
-       usb_free_urb(port->read_urb);
        usb_kill_urb(port->write_urb);
-       usb_free_urb(port->write_urb);
        usb_kill_urb(port->interrupt_in_urb);
-       usb_free_urb(port->interrupt_in_urb);
        usb_kill_urb(port->interrupt_out_urb);
+}
+
+static void port_free(struct usb_serial_port *port)
+{
+       kill_traffic(port);
+       usb_free_urb(port->read_urb);
+       usb_free_urb(port->write_urb);
+       usb_free_urb(port->interrupt_in_urb);
        usb_free_urb(port->interrupt_out_urb);
        kfree(port->bulk_in_buffer);
        kfree(port->bulk_out_buffer);
@@ -596,6 +612,39 @@ static struct usb_serial * create_serial (struct usb_device *dev,
        return serial;
 }
 
+static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
+                                                   struct usb_serial_driver *drv)
+{
+       struct usb_dynid *dynid;
+
+       spin_lock(&drv->dynids.lock);
+       list_for_each_entry(dynid, &drv->dynids.list, node) {
+               if (usb_match_one_id(intf, &dynid->id)) {
+                       spin_unlock(&drv->dynids.lock);
+                       return &dynid->id;
+               }
+       }
+       spin_unlock(&drv->dynids.lock);
+       return NULL;
+}
+
+static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
+                                               struct usb_interface *intf)
+{
+       const struct usb_device_id *id;
+
+       id = usb_match_id(intf, drv->id_table);
+       if (id) {
+               dbg("static descriptor matches");
+               goto exit;
+       }
+       id = match_dynamic_id(intf, drv);
+       if (id)
+               dbg("dynamic descriptor matches");
+exit:
+       return id;
+}
+
 static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
 {
        struct list_head *p;
@@ -605,11 +654,9 @@ static struct usb_serial_driver *search_serial_device(struct usb_interface *ifac
        /* Check if the usb id matches a known device */
        list_for_each(p, &usb_serial_driver_list) {
                t = list_entry(p, struct usb_serial_driver, driver_list);
-               id = usb_match_id(iface, t->id_table);
-               if (id != NULL) {
-                       dbg("descriptor matches");
+               id = get_iface_id(t, iface);
+               if (id)
                        return t;
-               }
        }
 
        return NULL;
@@ -639,14 +686,17 @@ int usb_serial_probe(struct usb_interface *interface,
        int num_ports = 0;
        int max_endpoints;
 
+       lock_kernel(); /* guard against unloading a serial driver module */
        type = search_serial_device(interface);
        if (!type) {
+               unlock_kernel();
                dbg("none matched");
                return -ENODEV;
        }
 
        serial = create_serial (dev, interface, type);
        if (!serial) {
+               unlock_kernel();
                dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
                return -ENOMEM;
        }
@@ -656,16 +706,18 @@ int usb_serial_probe(struct usb_interface *interface,
                const struct usb_device_id *id;
 
                if (!try_module_get(type->driver.owner)) {
+                       unlock_kernel();
                        dev_err(&interface->dev, "module get failed, exiting\n");
                        kfree (serial);
                        return -EIO;
                }
 
-               id = usb_match_id(interface, type->id_table);
+               id = get_iface_id(type, interface);
                retval = type->probe(serial, id);
                module_put(type->driver.owner);
 
                if (retval) {
+                       unlock_kernel();
                        dbg ("sub driver rejected device");
                        kfree (serial);
                        return retval;
@@ -735,6 +787,7 @@ int usb_serial_probe(struct usb_interface *interface,
                 * properly during a later invocation of usb_serial_probe
                 */
                if (num_bulk_in == 0 || num_bulk_out == 0) {
+                       unlock_kernel();
                        dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
                        kfree (serial);
                        return -ENODEV;
@@ -750,6 +803,7 @@ int usb_serial_probe(struct usb_interface *interface,
        if (type == &usb_serial_generic_device) {
                num_ports = num_bulk_out;
                if (num_ports == 0) {
+                       unlock_kernel();
                        dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
                        kfree (serial);
                        return -EIO;
@@ -760,6 +814,7 @@ int usb_serial_probe(struct usb_interface *interface,
                /* if this device type has a calc_num_ports function, call it */
                if (type->calc_num_ports) {
                        if (!try_module_get(type->driver.owner)) {
+                               unlock_kernel();
                                dev_err(&interface->dev, "module get failed, exiting\n");
                                kfree (serial);
                                return -EIO;
@@ -771,12 +826,6 @@ int usb_serial_probe(struct usb_interface *interface,
                        num_ports = type->num_ports;
        }
 
-       if (get_free_serial (serial, num_ports, &minor) == NULL) {
-               dev_err(&interface->dev, "No more free serial devices\n");
-               kfree (serial);
-               return -ENOMEM;
-       }
-
        serial->minor = minor;
        serial->num_ports = num_ports;
        serial->num_bulk_in = num_bulk_in;
@@ -791,6 +840,8 @@ int usb_serial_probe(struct usb_interface *interface,
        max_endpoints = max(max_endpoints, num_interrupt_out);
        max_endpoints = max(max_endpoints, (int)serial->num_ports);
        serial->num_port_pointers = max_endpoints;
+       unlock_kernel();
+
        dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
        for (i = 0; i < max_endpoints; ++i) {
                port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
@@ -925,6 +976,11 @@ int usb_serial_probe(struct usb_interface *interface,
                }
        }
 
+       if (get_free_serial (serial, num_ports, &minor) == NULL) {
+               dev_err(&interface->dev, "No more free serial devices\n");
+               goto probe_error;
+       }
+
        /* register all of the individual ports with the driver core */
        for (i = 0; i < num_ports; ++i) {
                port = serial->port[i];
@@ -1002,8 +1058,11 @@ void usb_serial_disconnect(struct usb_interface *interface)
        if (serial) {
                for (i = 0; i < serial->num_ports; ++i) {
                        port = serial->port[i];
-                       if (port && port->tty)
-                               tty_hangup(port->tty);
+                       if (port) {
+                               if (port->tty)
+                                       tty_hangup(port->tty);
+                               kill_traffic(port);
+                       }
                }
                /* let the last holder of this object 
                 * cause it to be cleaned up */
@@ -1040,6 +1099,7 @@ static int __init usb_serial_init(void)
                return -ENOMEM;
 
        /* Initialize our global data */
+       spin_lock_init(&table_lock);
        for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
                serial_table[i] = NULL;
        }
@@ -1138,7 +1198,7 @@ static void fixup_generic(struct usb_serial_driver *device)
        set_to_generic_if_null(device, shutdown);
 }
 
-int usb_serial_register(struct usb_serial_driver *driver)
+int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
 {
        int retval;
 
@@ -1162,7 +1222,7 @@ int usb_serial_register(struct usb_serial_driver *driver)
 }
 
 
-void usb_serial_deregister(struct usb_serial_driver *device)
+void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */
 {
        info("USB Serial deregistering driver %s", device->description);
        list_del(&device->driver_list);
index b09f060..2f59ff2 100644 (file)
@@ -90,8 +90,6 @@ static struct usb_device_id id_table [] = {
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID),
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
-       { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID),
-               .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID),
                .driver_info = (kernel_ulong_t)&palm_os_4_probe },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID),
@@ -151,7 +149,6 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
-       { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) },
        { USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
        { USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
@@ -189,6 +186,7 @@ static struct usb_serial_driver handspring_device = {
                .name =         "visor",
        },
        .description =          "Handspring Visor / Palm OS",
+       .usb_driver =           &visor_driver,
        .id_table =             id_table,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          2,
@@ -219,6 +217,7 @@ static struct usb_serial_driver clie_5_device = {
                .name =         "clie_5",
        },
        .description =          "Sony Clie 5.0",
+       .usb_driver =           &visor_driver,
        .id_table =             clie_id_5_table,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          2,
@@ -249,6 +248,7 @@ static struct usb_serial_driver clie_3_5_device = {
                .name =         "clie_3.5",
        },
        .description =          "Sony Clie 3.5",
+       .usb_driver =           &visor_driver,
        .id_table =             clie_id_3_5_table,
        .num_interrupt_in =     0,
        .num_bulk_in =          1,
index 765118d..4ce6f62 100644 (file)
@@ -32,7 +32,6 @@
 #define PALM_TUNGSTEN_T_ID             0x0060
 #define PALM_TREO_650                  0x0061
 #define PALM_TUNGSTEN_Z_ID             0x0031
-#define PALM_ZIRE31_ID                 0x0061
 #define PALM_ZIRE_ID                   0x0070
 #define PALM_M100_ID                   0x0080
 
index 5483d85..bf16e9e 100644 (file)
@@ -161,6 +161,7 @@ static struct usb_serial_driver whiteheat_fake_device = {
                .name =         "whiteheatnofirm",
        },
        .description =          "Connect Tech - WhiteHEAT - (prerenumeration)",
+       .usb_driver =           &whiteheat_driver,
        .id_table =             id_table_prerenumeration,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
@@ -176,6 +177,7 @@ static struct usb_serial_driver whiteheat_device = {
                .name =         "whiteheat",
        },
        .description =          "Connect Tech - WhiteHEAT",
+       .usb_driver =           &whiteheat_driver,
        .id_table =             id_table_std,
        .num_interrupt_in =     NUM_DONT_CARE,
        .num_bulk_in =          NUM_DONT_CARE,
index e565d3d..6d3dad3 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/usb_ch9.h>
 #include <linux/usb/input.h>
 #include "usb.h"
 #include "onetouch.h"
index e1072d5..70234f5 100644 (file)
@@ -110,23 +110,6 @@ static int slave_configure(struct scsi_device *sdev)
         * the end, scatter-gather buffers follow page boundaries. */
        blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
 
-       /* Set the SCSI level to at least 2.  We'll leave it at 3 if that's
-        * what is originally reported.  We need this to avoid confusing
-        * the SCSI layer with devices that report 0 or 1, but need 10-byte
-        * commands (ala ATAPI devices behind certain bridges, or devices
-        * which simply have broken INQUIRY data).
-        *
-        * NOTE: This means /dev/sg programs (ala cdrecord) will get the
-        * actual information.  This seems to be the preference for
-        * programs like that.
-        *
-        * NOTE: This also means that /proc/scsi/scsi and sysfs may report
-        * the actual value or the modified one, depending on where the
-        * data comes from.
-        */
-       if (sdev->scsi_level < SCSI_2)
-               sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
-
        /* Many devices have trouble transfering more than 32KB at a time,
         * while others have trouble with more than 64K. At this time we
         * are limiting both to 32K (64 sectores).
@@ -176,7 +159,9 @@ static int slave_configure(struct scsi_device *sdev)
                 * a Get-Max-LUN request, we won't lose much by setting the
                 * revision level down to 2.  The only devices that would be
                 * affected are those with sparse LUNs. */
-               sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
+               if (sdev->scsi_level > SCSI_2)
+                       sdev->sdev_target->scsi_level =
+                                       sdev->scsi_level = SCSI_2;
 
                /* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
                 * Hardware Error) when any low-level error occurs,
@@ -194,6 +179,16 @@ static int slave_configure(struct scsi_device *sdev)
                sdev->use_10_for_ms = 1;
        }
 
+       /* The CB and CBI transports have no way to pass LUN values
+        * other than the bits in the second byte of a CDB.  But those
+        * bits don't get set to the LUN value if the device reports
+        * scsi_level == 0 (UNKNOWN).  Hence such devices must necessarily
+        * be single-LUN.
+        */
+       if ((us->protocol == US_PR_CB || us->protocol == US_PR_CBI) &&
+                       sdev->scsi_level == SCSI_UNKNOWN)
+               us->max_lun = 0;
+
        /* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
         * REMOVAL command, so suppress those commands. */
        if (us->flags & US_FL_NOT_LOCKABLE)
index b49f2a7..f49a62f 100644 (file)
@@ -573,7 +573,7 @@ UNUSUAL_DEV(  0x054c, 0x002b, 0x0100, 0x0110,
 #endif
 
 /* Submitted by Olaf Hering, <olh@suse.de> SuSE Bugzilla #49049 */
-UNUSUAL_DEV(  0x054c, 0x002c, 0x0501, 0x0501,
+UNUSUAL_DEV(  0x054c, 0x002c, 0x0501, 0x2000,
                "Sony",
                "USB Floppy Drive",
                US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -1325,13 +1325,6 @@ UNUSUAL_DEV(  0x0fce, 0xe031, 0x0000, 0x0000,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                US_FL_FIX_CAPACITY ),
 
-/* Reported by Jan Mate <mate@fiit.stuba.sk> */
-UNUSUAL_DEV(  0x0fce, 0xe030, 0x0000, 0x0000,
-               "Sony Ericsson",
-               "P990i",
-               US_SC_DEVICE, US_PR_DEVICE, NULL,
-               US_FL_FIX_CAPACITY ),
-
 /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
  * Tested on hardware version 1.10.
  * Entry is needed only for the initializer function override.
index 7064450..7e7ec29 100644 (file)
@@ -731,26 +731,27 @@ static int get_pipes(struct us_data *us)
        struct usb_endpoint_descriptor *ep_int = NULL;
 
        /*
-        * Find the endpoints we need.
+        * Find the first endpoint of each type we need.
         * We are expecting a minimum of 2 endpoints - in and out (bulk).
-        * An optional interrupt is OK (necessary for CBI protocol).
+        * An optional interrupt-in is OK (necessary for CBI protocol).
         * We will ignore any others.
         */
        for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
                ep = &altsetting->endpoint[i].desc;
 
-               /* Is it a BULK endpoint? */
                if (usb_endpoint_xfer_bulk(ep)) {
-                       /* BULK in or out? */
-                       if (usb_endpoint_dir_in(ep))
-                               ep_in = ep;
-                       else
-                               ep_out = ep;
+                       if (usb_endpoint_dir_in(ep)) {
+                               if (!ep_in)
+                                       ep_in = ep;
+                       } else {
+                               if (!ep_out)
+                                       ep_out = ep;
+                       }
                }
 
-               /* Is it an interrupt endpoint? */
-               else if (usb_endpoint_xfer_int(ep)) {
-                       ep_int = ep;
+               else if (usb_endpoint_is_int_in(ep)) {
+                       if (!ep_int)
+                               ep_int = ep;
                }
        }
 
diff --git a/drivers/video/output.c b/drivers/video/output.c
new file mode 100644 (file)
index 0000000..1473f2c
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ *  output.c - Display Output Switch driver
+ *
+ *  Copyright (C) 2006 Luming Yu <luming.yu@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 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/video_output.h>
+#include <linux/err.h>
+#include <linux/ctype.h>
+
+
+MODULE_DESCRIPTION("Display Output Switcher Lowlevel Control Abstraction");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Luming Yu <luming.yu@intel.com>");
+
+static ssize_t video_output_show_state(struct class_device *dev,char *buf)
+{
+       ssize_t ret_size = 0;
+       struct output_device *od = to_output_device(dev);
+       if (od->props)
+               ret_size = sprintf(buf,"%.8x\n",od->props->get_status(od));
+       return ret_size;
+}
+
+static ssize_t video_output_store_state(struct class_device *dev,
+       const char *buf,size_t count)
+{
+       char *endp;
+       struct output_device *od = to_output_device(dev);
+       int request_state = simple_strtoul(buf,&endp,0);
+       size_t size = endp - buf;
+
+       if (*endp && isspace(*endp))
+               size++;
+       if (size != count)
+               return -EINVAL;
+
+       if (od->props) {
+               od->request_state = request_state;
+               od->props->set_state(od);
+       }
+       return count;
+}
+
+static void video_output_class_release(struct class_device *dev)
+{
+       struct output_device *od = to_output_device(dev);
+       kfree(od);
+}
+
+static struct class_device_attribute video_output_attributes[] = {
+       __ATTR(state, 0644, video_output_show_state, video_output_store_state),
+       __ATTR_NULL,
+};
+
+static struct class video_output_class = {
+       .name = "video_output",
+       .release = video_output_class_release,
+       .class_dev_attrs = video_output_attributes,
+};
+
+struct output_device *video_output_register(const char *name,
+       struct device *dev,
+       void *devdata,
+       struct output_properties *op)
+{
+       struct output_device *new_dev;
+       int ret_code = 0;
+
+       new_dev = kzalloc(sizeof(struct output_device),GFP_KERNEL);
+       if (!new_dev) {
+               ret_code = -ENOMEM;
+               goto error_return;
+       }
+       new_dev->props = op;
+       new_dev->class_dev.class = &video_output_class;
+       new_dev->class_dev.dev = dev;
+       strlcpy(new_dev->class_dev.class_id,name,KOBJ_NAME_LEN);
+       class_set_devdata(&new_dev->class_dev,devdata);
+       ret_code = class_device_register(&new_dev->class_dev);
+       if (ret_code) {
+               kfree(new_dev);
+               goto error_return;
+       }
+       return new_dev;
+
+error_return:
+       return ERR_PTR(ret_code);
+}
+EXPORT_SYMBOL(video_output_register);
+
+void video_output_unregister(struct output_device *dev)
+{
+       if (!dev)
+               return;
+       class_device_unregister(&dev->class_dev);
+}
+EXPORT_SYMBOL(video_output_unregister);
+
+static void __exit video_output_class_exit(void)
+{
+       class_unregister(&video_output_class);
+}
+
+static int __init video_output_class_init(void)
+{
+       return class_register(&video_output_class);
+}
+
+postcore_initcall(video_output_class_init);
+module_exit(video_output_class_exit);
index d04d2f7..85e3850 100644 (file)
@@ -1,6 +1,8 @@
 Version 1.47
 ------------
 Fix oops in list_del during mount caused by unaligned string.
+Seek to SEEK_END forces check for update of file size for non-cached
+files.
 
 Version 1.46
 ------------
index 10c9029..93ef099 100644 (file)
@@ -511,7 +511,15 @@ static loff_t cifs_llseek(struct file *file, loff_t offset, int origin)
 {
        /* origin == SEEK_END => we must revalidate the cached file length */
        if (origin == SEEK_END) {
-               int retval = cifs_revalidate(file->f_path.dentry);
+               int retval;
+
+               /* some applications poll for the file length in this strange
+                  way so we must seek to end on non-oplocked files by
+                  setting the revalidate time to zero */
+               if(file->f_path.dentry->d_inode)                
+                       CIFS_I(file->f_path.dentry->d_inode)->time = 0;
+
+               retval = cifs_revalidate(file->f_path.dentry);
                if (retval < 0)
                        return (loff_t)retval;
        }
index 8a49b2e..e9dcf5e 100644 (file)
@@ -1146,7 +1146,7 @@ static int cifs_writepages(struct address_space *mapping,
        pgoff_t end;
        pgoff_t index;
        int range_whole = 0;
-       struct kvec iov[32];
+       struct kvec * iov;
        int len;
        int n_iov = 0;
        pgoff_t next;
@@ -1171,15 +1171,21 @@ static int cifs_writepages(struct address_space *mapping,
        if((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))
                if(cifs_sb->tcon->ses->server->secMode &
                           (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-                       if(!experimEnabled)
+                       if(!experimEnabled) 
                                return generic_writepages(mapping, wbc);
 
+       iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);
+       if(iov == NULL)
+               return generic_writepages(mapping, wbc);
+
+
        /*
         * BB: Is this meaningful for a non-block-device file system?
         * If it is, we should test it again after we do I/O
         */
        if (wbc->nonblocking && bdi_write_congested(bdi)) {
                wbc->encountered_congestion = 1;
+               kfree(iov);
                return 0;
        }
 
@@ -1345,7 +1351,7 @@ retry:
                mapping->writeback_index = index;
 
        FreeXid(xid);
-
+       kfree(iov);
        return rc;
 }
 
index 99dfb53..782940b 100644 (file)
@@ -156,9 +156,9 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type,
                tmp_inode->i_atime = cnvrtDosUnixTm(
                                le16_to_cpu(pfindData->LastAccessDate),
                                le16_to_cpu(pfindData->LastAccessTime));
-                tmp_inode->i_ctime = cnvrtDosUnixTm(
-                                le16_to_cpu(pfindData->LastWriteDate),
-                                le16_to_cpu(pfindData->LastWriteTime));
+               tmp_inode->i_ctime = cnvrtDosUnixTm(
+                               le16_to_cpu(pfindData->LastWriteDate),
+                               le16_to_cpu(pfindData->LastWriteTime));
                AdjustForTZ(cifs_sb->tcon, tmp_inode);
                attr = le16_to_cpu(pfindData->Attributes);
                allocation_size = le32_to_cpu(pfindData->AllocationSize);
index 7a1b2b9..1b1daf6 100644 (file)
@@ -196,7 +196,7 @@ dohash(char *out, char *in, char *key, int forw)
        char c[28];
        char d[28];
        char *cd;
-       char ki[16][48];
+       char (*ki)[48];
        char *pd1;
        char l[32], r[32];
        char *rl;
@@ -206,6 +206,12 @@ dohash(char *out, char *in, char *key, int forw)
        if(pk1 == NULL)
                return;
 
+       ki = kmalloc(16*48, GFP_KERNEL);
+       if(ki == NULL) {
+               kfree(pk1);
+               return;
+       }
+
        cd = pk1 + 56;
        pd1= cd  + 56;
        rl = pd1 + 64;
@@ -243,6 +249,7 @@ dohash(char *out, char *in, char *key, int forw)
                er = kmalloc(48+48+32+32+32, GFP_KERNEL);
                if(er == NULL) {
                        kfree(pk1);
+                       kfree(ki);
                        return;
                }
                erk = er+48;
@@ -290,6 +297,7 @@ dohash(char *out, char *in, char *key, int forw)
 
        permute(out, rl, perm6, 64);
        kfree(pk1);
+       kfree(ki);
 }
 
 static void
index b5654a2..6fa7b0d 100644 (file)
@@ -3,21 +3,21 @@ menu "Distributed Lock Manager"
 
 config DLM
        tristate "Distributed Lock Manager (DLM)"
-       depends on IPV6 || IPV6=n
+       depends on SYSFS && (IPV6 || IPV6=n)
        select CONFIGFS_FS
        select IP_SCTP if DLM_SCTP
        help
-       A general purpose distributed lock manager for kernel or userspace
-       applications.
+         A general purpose distributed lock manager for kernel or userspace
+         applications.
 
 choice
        prompt "Select DLM communications protocol"
        depends on DLM
        default DLM_TCP
        help
-       The DLM Can use TCP or SCTP for it's network communications.
-       SCTP supports multi-homed operations whereas TCP doesn't.
-       However, SCTP seems to have stability problems at the moment.
+         The DLM Can use TCP or SCTP for it's network communications.
+         SCTP supports multi-homed operations whereas TCP doesn't.
+         However, SCTP seems to have stability problems at the moment.
 
 config DLM_TCP
        bool "TCP/IP"
@@ -31,8 +31,8 @@ config DLM_DEBUG
        bool "DLM debugging"
        depends on DLM
        help
-       Under the debugfs mount point, the name of each lockspace will
-       appear as a file in the "dlm" directory.  The output is the
-       list of resource and locks the local node knows about.
+         Under the debugfs mount point, the name of each lockspace will
+         appear as a file in the "dlm" directory.  The output is the
+         list of resource and locks the local node knows about.
 
 endmenu
index 8855305..8665c88 100644 (file)
@@ -54,6 +54,11 @@ static struct config_item *make_node(struct config_group *, const char *);
 static void drop_node(struct config_group *, struct config_item *);
 static void release_node(struct config_item *);
 
+static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a,
+                           char *buf);
+static ssize_t store_cluster(struct config_item *i,
+                            struct configfs_attribute *a,
+                            const char *buf, size_t len);
 static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
                         char *buf);
 static ssize_t store_comm(struct config_item *i, struct configfs_attribute *a,
@@ -73,6 +78,101 @@ static ssize_t node_nodeid_write(struct node *nd, const char *buf, size_t len);
 static ssize_t node_weight_read(struct node *nd, char *buf);
 static ssize_t node_weight_write(struct node *nd, const char *buf, size_t len);
 
+struct cluster {
+       struct config_group group;
+       unsigned int cl_tcp_port;
+       unsigned int cl_buffer_size;
+       unsigned int cl_rsbtbl_size;
+       unsigned int cl_lkbtbl_size;
+       unsigned int cl_dirtbl_size;
+       unsigned int cl_recover_timer;
+       unsigned int cl_toss_secs;
+       unsigned int cl_scan_secs;
+       unsigned int cl_log_debug;
+};
+
+enum {
+       CLUSTER_ATTR_TCP_PORT = 0,
+       CLUSTER_ATTR_BUFFER_SIZE,
+       CLUSTER_ATTR_RSBTBL_SIZE,
+       CLUSTER_ATTR_LKBTBL_SIZE,
+       CLUSTER_ATTR_DIRTBL_SIZE,
+       CLUSTER_ATTR_RECOVER_TIMER,
+       CLUSTER_ATTR_TOSS_SECS,
+       CLUSTER_ATTR_SCAN_SECS,
+       CLUSTER_ATTR_LOG_DEBUG,
+};
+
+struct cluster_attribute {
+       struct configfs_attribute attr;
+       ssize_t (*show)(struct cluster *, char *);
+       ssize_t (*store)(struct cluster *, const char *, size_t);
+};
+
+static ssize_t cluster_set(struct cluster *cl, unsigned int *cl_field,
+                          unsigned int *info_field, int check_zero,
+                          const char *buf, size_t len)
+{
+       unsigned int x;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+
+       x = simple_strtoul(buf, NULL, 0);
+
+       if (check_zero && !x)
+               return -EINVAL;
+
+       *cl_field = x;
+       *info_field = x;
+
+       return len;
+}
+
+#define __CONFIGFS_ATTR(_name,_mode,_read,_write) {                           \
+       .attr   = { .ca_name = __stringify(_name),                            \
+                   .ca_mode = _mode,                                         \
+                   .ca_owner = THIS_MODULE },                                \
+       .show   = _read,                                                      \
+       .store  = _write,                                                     \
+}
+
+#define CLUSTER_ATTR(name, check_zero)                                        \
+static ssize_t name##_write(struct cluster *cl, const char *buf, size_t len)  \
+{                                                                             \
+       return cluster_set(cl, &cl->cl_##name, &dlm_config.ci_##name,         \
+                          check_zero, buf, len);                             \
+}                                                                             \
+static ssize_t name##_read(struct cluster *cl, char *buf)                     \
+{                                                                             \
+       return snprintf(buf, PAGE_SIZE, "%u\n", cl->cl_##name);               \
+}                                                                             \
+static struct cluster_attribute cluster_attr_##name =                         \
+__CONFIGFS_ATTR(name, 0644, name##_read, name##_write)
+
+CLUSTER_ATTR(tcp_port, 1);
+CLUSTER_ATTR(buffer_size, 1);
+CLUSTER_ATTR(rsbtbl_size, 1);
+CLUSTER_ATTR(lkbtbl_size, 1);
+CLUSTER_ATTR(dirtbl_size, 1);
+CLUSTER_ATTR(recover_timer, 1);
+CLUSTER_ATTR(toss_secs, 1);
+CLUSTER_ATTR(scan_secs, 1);
+CLUSTER_ATTR(log_debug, 0);
+
+static struct configfs_attribute *cluster_attrs[] = {
+       [CLUSTER_ATTR_TCP_PORT] = &cluster_attr_tcp_port.attr,
+       [CLUSTER_ATTR_BUFFER_SIZE] = &cluster_attr_buffer_size.attr,
+       [CLUSTER_ATTR_RSBTBL_SIZE] = &cluster_attr_rsbtbl_size.attr,
+       [CLUSTER_ATTR_LKBTBL_SIZE] = &cluster_attr_lkbtbl_size.attr,
+       [CLUSTER_ATTR_DIRTBL_SIZE] = &cluster_attr_dirtbl_size.attr,
+       [CLUSTER_ATTR_RECOVER_TIMER] = &cluster_attr_recover_timer.attr,
+       [CLUSTER_ATTR_TOSS_SECS] = &cluster_attr_toss_secs.attr,
+       [CLUSTER_ATTR_SCAN_SECS] = &cluster_attr_scan_secs.attr,
+       [CLUSTER_ATTR_LOG_DEBUG] = &cluster_attr_log_debug.attr,
+       NULL,
+};
+
 enum {
        COMM_ATTR_NODEID = 0,
        COMM_ATTR_LOCAL,
@@ -152,10 +252,6 @@ struct clusters {
        struct configfs_subsystem subsys;
 };
 
-struct cluster {
-       struct config_group group;
-};
-
 struct spaces {
        struct config_group ss_group;
 };
@@ -197,6 +293,8 @@ static struct configfs_group_operations clusters_ops = {
 
 static struct configfs_item_operations cluster_ops = {
        .release = release_cluster,
+       .show_attribute = show_cluster,
+       .store_attribute = store_cluster,
 };
 
 static struct configfs_group_operations spaces_ops = {
@@ -237,6 +335,7 @@ static struct config_item_type clusters_type = {
 
 static struct config_item_type cluster_type = {
        .ct_item_ops = &cluster_ops,
+       .ct_attrs = cluster_attrs,
        .ct_owner = THIS_MODULE,
 };
 
@@ -317,6 +416,16 @@ static struct config_group *make_cluster(struct config_group *g,
        cl->group.default_groups[1] = &cms->cs_group;
        cl->group.default_groups[2] = NULL;
 
+       cl->cl_tcp_port = dlm_config.ci_tcp_port;
+       cl->cl_buffer_size = dlm_config.ci_buffer_size;
+       cl->cl_rsbtbl_size = dlm_config.ci_rsbtbl_size;
+       cl->cl_lkbtbl_size = dlm_config.ci_lkbtbl_size;
+       cl->cl_dirtbl_size = dlm_config.ci_dirtbl_size;
+       cl->cl_recover_timer = dlm_config.ci_recover_timer;
+       cl->cl_toss_secs = dlm_config.ci_toss_secs;
+       cl->cl_scan_secs = dlm_config.ci_scan_secs;
+       cl->cl_log_debug = dlm_config.ci_log_debug;
+
        space_list = &sps->ss_group;
        comm_list = &cms->cs_group;
        return &cl->group;
@@ -509,6 +618,25 @@ void dlm_config_exit(void)
  * Functions for user space to read/write attributes
  */
 
+static ssize_t show_cluster(struct config_item *i, struct configfs_attribute *a,
+                           char *buf)
+{
+       struct cluster *cl = to_cluster(i);
+       struct cluster_attribute *cla =
+                       container_of(a, struct cluster_attribute, attr);
+       return cla->show ? cla->show(cl, buf) : 0;
+}
+
+static ssize_t store_cluster(struct config_item *i,
+                            struct configfs_attribute *a,
+                            const char *buf, size_t len)
+{
+       struct cluster *cl = to_cluster(i);
+       struct cluster_attribute *cla =
+               container_of(a, struct cluster_attribute, attr);
+       return cla->store ? cla->store(cl, buf, len) : -EINVAL;
+}
+
 static ssize_t show_comm(struct config_item *i, struct configfs_attribute *a,
                         char *buf)
 {
@@ -775,15 +903,17 @@ int dlm_our_addr(struct sockaddr_storage *addr, int num)
 #define DEFAULT_RECOVER_TIMER      5
 #define DEFAULT_TOSS_SECS         10
 #define DEFAULT_SCAN_SECS          5
+#define DEFAULT_LOG_DEBUG          0
 
 struct dlm_config_info dlm_config = {
-       .tcp_port = DEFAULT_TCP_PORT,
-       .buffer_size = DEFAULT_BUFFER_SIZE,
-       .rsbtbl_size = DEFAULT_RSBTBL_SIZE,
-       .lkbtbl_size = DEFAULT_LKBTBL_SIZE,
-       .dirtbl_size = DEFAULT_DIRTBL_SIZE,
-       .recover_timer = DEFAULT_RECOVER_TIMER,
-       .toss_secs = DEFAULT_TOSS_SECS,
-       .scan_secs = DEFAULT_SCAN_SECS
+       .ci_tcp_port = DEFAULT_TCP_PORT,
+       .ci_buffer_size = DEFAULT_BUFFER_SIZE,
+       .ci_rsbtbl_size = DEFAULT_RSBTBL_SIZE,
+       .ci_lkbtbl_size = DEFAULT_LKBTBL_SIZE,
+       .ci_dirtbl_size = DEFAULT_DIRTBL_SIZE,
+       .ci_recover_timer = DEFAULT_RECOVER_TIMER,
+       .ci_toss_secs = DEFAULT_TOSS_SECS,
+       .ci_scan_secs = DEFAULT_SCAN_SECS,
+       .ci_log_debug = DEFAULT_LOG_DEBUG
 };
 
index 9da7839..1e97861 100644 (file)
 #define DLM_MAX_ADDR_COUNT 3
 
 struct dlm_config_info {
-       int tcp_port;
-       int buffer_size;
-       int rsbtbl_size;
-       int lkbtbl_size;
-       int dirtbl_size;
-       int recover_timer;
-       int toss_secs;
-       int scan_secs;
+       int ci_tcp_port;
+       int ci_buffer_size;
+       int ci_rsbtbl_size;
+       int ci_lkbtbl_size;
+       int ci_dirtbl_size;
+       int ci_recover_timer;
+       int ci_toss_secs;
+       int ci_scan_secs;
+       int ci_log_debug;
 };
 
 extern struct dlm_config_info dlm_config;
index 1ee8195..61d9320 100644 (file)
@@ -41,6 +41,7 @@
 #include <asm/uaccess.h>
 
 #include <linux/dlm.h>
+#include "config.h"
 
 #define DLM_LOCKSPACE_LEN      64
 
@@ -69,12 +70,12 @@ struct dlm_mhandle;
 #define log_error(ls, fmt, args...) \
        printk(KERN_ERR "dlm: %s: " fmt "\n", (ls)->ls_name , ##args)
 
-#define DLM_LOG_DEBUG
-#ifdef DLM_LOG_DEBUG
-#define log_debug(ls, fmt, args...) log_error(ls, fmt, ##args)
-#else
-#define log_debug(ls, fmt, args...)
-#endif
+#define log_debug(ls, fmt, args...) \
+do { \
+       if (dlm_config.ci_log_debug) \
+               printk(KERN_DEBUG "dlm: %s: " fmt "\n", \
+                      (ls)->ls_name , ##args); \
+} while (0)
 
 #define DLM_ASSERT(x, do) \
 { \
@@ -309,8 +310,8 @@ static inline int rsb_flag(struct dlm_rsb *r, enum rsb_flags flag)
 
 /* dlm_header is first element of all structs sent between nodes */
 
-#define DLM_HEADER_MAJOR       0x00020000
-#define DLM_HEADER_MINOR       0x00000001
+#define DLM_HEADER_MAJOR       0x00030000
+#define DLM_HEADER_MINOR       0x00000000
 
 #define DLM_MSG                        1
 #define DLM_RCOM               2
@@ -386,6 +387,8 @@ struct dlm_rcom {
        uint32_t                rc_type;        /* DLM_RCOM_ */
        int                     rc_result;      /* multi-purpose */
        uint64_t                rc_id;          /* match reply with request */
+       uint64_t                rc_seq;         /* sender's ls_recover_seq */
+       uint64_t                rc_seq_reply;   /* remote ls_recover_seq */
        char                    rc_buf[0];
 };
 
@@ -523,6 +526,7 @@ struct dlm_user_proc {
        spinlock_t              asts_spin;
        struct list_head        locks;
        spinlock_t              locks_spin;
+       struct list_head        unlocking;
        wait_queue_head_t       wait;
 };
 
index 30878de..e725005 100644 (file)
@@ -754,6 +754,11 @@ static void add_to_waiters(struct dlm_lkb *lkb, int mstype)
        mutex_unlock(&ls->ls_waiters_mutex);
 }
 
+/* We clear the RESEND flag because we might be taking an lkb off the waiters
+   list as part of process_requestqueue (e.g. a lookup that has an optimized
+   request reply on the requestqueue) between dlm_recover_waiters_pre() which
+   set RESEND and dlm_recover_waiters_post() */
+
 static int _remove_from_waiters(struct dlm_lkb *lkb)
 {
        int error = 0;
@@ -764,6 +769,7 @@ static int _remove_from_waiters(struct dlm_lkb *lkb)
                goto out;
        }
        lkb->lkb_wait_type = 0;
+       lkb->lkb_flags &= ~DLM_IFL_RESEND;
        list_del(&lkb->lkb_wait_reply);
        unhold_lkb(lkb);
  out:
@@ -810,7 +816,7 @@ static int shrink_bucket(struct dlm_ls *ls, int b)
                list_for_each_entry_reverse(r, &ls->ls_rsbtbl[b].toss,
                                            res_hashchain) {
                        if (!time_after_eq(jiffies, r->res_toss_time +
-                                          dlm_config.toss_secs * HZ))
+                                          dlm_config.ci_toss_secs * HZ))
                                continue;
                        found = 1;
                        break;
@@ -2144,12 +2150,24 @@ static void send_args(struct dlm_rsb *r, struct dlm_lkb *lkb,
        if (lkb->lkb_astaddr)
                ms->m_asts |= AST_COMP;
 
-       if (ms->m_type == DLM_MSG_REQUEST || ms->m_type == DLM_MSG_LOOKUP)
-               memcpy(ms->m_extra, r->res_name, r->res_length);
+       /* compare with switch in create_message; send_remove() doesn't
+          use send_args() */
 
-       else if (lkb->lkb_lvbptr)
+       switch (ms->m_type) {
+       case DLM_MSG_REQUEST:
+       case DLM_MSG_LOOKUP:
+               memcpy(ms->m_extra, r->res_name, r->res_length);
+               break;
+       case DLM_MSG_CONVERT:
+       case DLM_MSG_UNLOCK:
+       case DLM_MSG_REQUEST_REPLY:
+       case DLM_MSG_CONVERT_REPLY:
+       case DLM_MSG_GRANT:
+               if (!lkb->lkb_lvbptr)
+                       break;
                memcpy(ms->m_extra, lkb->lkb_lvbptr, r->res_ls->ls_lvblen);
-
+               break;
+       }
 }
 
 static int send_common(struct dlm_rsb *r, struct dlm_lkb *lkb, int mstype)
@@ -2418,8 +2436,12 @@ static int receive_request_args(struct dlm_ls *ls, struct dlm_lkb *lkb,
 
        DLM_ASSERT(is_master_copy(lkb), dlm_print_lkb(lkb););
 
-       if (receive_lvb(ls, lkb, ms))
-               return -ENOMEM;
+       if (lkb->lkb_exflags & DLM_LKF_VALBLK) {
+               /* lkb was just created so there won't be an lvb yet */
+               lkb->lkb_lvbptr = allocate_lvb(ls);
+               if (!lkb->lkb_lvbptr)
+                       return -ENOMEM;
+       }
 
        return 0;
 }
@@ -3002,7 +3024,7 @@ int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery)
 {
        struct dlm_message *ms = (struct dlm_message *) hd;
        struct dlm_ls *ls;
-       int error;
+       int error = 0;
 
        if (!recovery)
                dlm_message_in(ms);
@@ -3119,7 +3141,7 @@ int dlm_receive_message(struct dlm_header *hd, int nodeid, int recovery)
  out:
        dlm_put_lockspace(ls);
        dlm_astd_wake();
-       return 0;
+       return error;
 }
 
 
@@ -3132,6 +3154,7 @@ static void recover_convert_waiter(struct dlm_ls *ls, struct dlm_lkb *lkb)
        if (middle_conversion(lkb)) {
                hold_lkb(lkb);
                ls->ls_stub_ms.m_result = -EINPROGRESS;
+               ls->ls_stub_ms.m_flags = lkb->lkb_flags;
                _remove_from_waiters(lkb);
                _receive_convert_reply(lkb, &ls->ls_stub_ms);
 
@@ -3205,6 +3228,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
                case DLM_MSG_UNLOCK:
                        hold_lkb(lkb);
                        ls->ls_stub_ms.m_result = -DLM_EUNLOCK;
+                       ls->ls_stub_ms.m_flags = lkb->lkb_flags;
                        _remove_from_waiters(lkb);
                        _receive_unlock_reply(lkb, &ls->ls_stub_ms);
                        dlm_put_lkb(lkb);
@@ -3213,6 +3237,7 @@ void dlm_recover_waiters_pre(struct dlm_ls *ls)
                case DLM_MSG_CANCEL:
                        hold_lkb(lkb);
                        ls->ls_stub_ms.m_result = -DLM_ECANCEL;
+                       ls->ls_stub_ms.m_flags = lkb->lkb_flags;
                        _remove_from_waiters(lkb);
                        _receive_cancel_reply(lkb, &ls->ls_stub_ms);
                        dlm_put_lkb(lkb);
@@ -3571,6 +3596,14 @@ int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
        lock_rsb(r);
 
        switch (error) {
+       case -EBADR:
+               /* There's a chance the new master received our lock before
+                  dlm_recover_master_reply(), this wouldn't happen if we did
+                  a barrier between recover_masters and recover_locks. */
+               log_debug(ls, "master copy not ready %x r %lx %s", lkb->lkb_id,
+                         (unsigned long)r, r->res_name);
+               dlm_send_rcom_lock(r, lkb);
+               goto out;
        case -EEXIST:
                log_debug(ls, "master copy exists %x", lkb->lkb_id);
                /* fall through */
@@ -3585,7 +3618,7 @@ int dlm_recover_process_copy(struct dlm_ls *ls, struct dlm_rcom *rc)
        /* an ack for dlm_recover_locks() which waits for replies from
           all the locks it sends to new masters */
        dlm_recovered_lock(r);
-
+ out:
        unlock_rsb(r);
        put_rsb(r);
        dlm_put_lkb(lkb);
@@ -3610,7 +3643,7 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua,
        }
 
        if (flags & DLM_LKF_VALBLK) {
-               ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
+               ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
                if (!ua->lksb.sb_lvbptr) {
                        kfree(ua);
                        __put_lkb(ls, lkb);
@@ -3679,7 +3712,7 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
        ua = (struct dlm_user_args *)lkb->lkb_astparam;
 
        if (flags & DLM_LKF_VALBLK && !ua->lksb.sb_lvbptr) {
-               ua->lksb.sb_lvbptr = kmalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
+               ua->lksb.sb_lvbptr = kzalloc(DLM_USER_LVB_LEN, GFP_KERNEL);
                if (!ua->lksb.sb_lvbptr) {
                        error = -ENOMEM;
                        goto out_put;
@@ -3745,12 +3778,10 @@ int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
                goto out_put;
 
        spin_lock(&ua->proc->locks_spin);
-       list_del_init(&lkb->lkb_ownqueue);
+       /* dlm_user_add_ast() may have already taken lkb off the proc list */
+       if (!list_empty(&lkb->lkb_ownqueue))
+               list_move(&lkb->lkb_ownqueue, &ua->proc->unlocking);
        spin_unlock(&ua->proc->locks_spin);
-
-       /* this removes the reference for the proc->locks list added by
-          dlm_user_request */
-       unhold_lkb(lkb);
  out_put:
        dlm_put_lkb(lkb);
  out:
@@ -3790,9 +3821,8 @@ int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
        /* this lkb was removed from the WAITING queue */
        if (lkb->lkb_grmode == DLM_LOCK_IV) {
                spin_lock(&ua->proc->locks_spin);
-               list_del_init(&lkb->lkb_ownqueue);
+               list_move(&lkb->lkb_ownqueue, &ua->proc->unlocking);
                spin_unlock(&ua->proc->locks_spin);
-               unhold_lkb(lkb);
        }
  out_put:
        dlm_put_lkb(lkb);
@@ -3853,11 +3883,6 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
        mutex_lock(&ls->ls_clear_proc_locks);
 
        list_for_each_entry_safe(lkb, safe, &proc->locks, lkb_ownqueue) {
-               if (lkb->lkb_ast_type) {
-                       list_del(&lkb->lkb_astqueue);
-                       unhold_lkb(lkb);
-               }
-
                list_del_init(&lkb->lkb_ownqueue);
 
                if (lkb->lkb_exflags & DLM_LKF_PERSISTENT) {
@@ -3874,6 +3899,20 @@ void dlm_clear_proc_locks(struct dlm_ls *ls, struct dlm_user_proc *proc)
 
                dlm_put_lkb(lkb);
        }
+
+       /* in-progress unlocks */
+       list_for_each_entry_safe(lkb, safe, &proc->unlocking, lkb_ownqueue) {
+               list_del_init(&lkb->lkb_ownqueue);
+               lkb->lkb_flags |= DLM_IFL_DEAD;
+               dlm_put_lkb(lkb);
+       }
+
+       list_for_each_entry_safe(lkb, safe, &proc->asts, lkb_astqueue) {
+               list_del(&lkb->lkb_astqueue);
+               dlm_put_lkb(lkb);
+       }
+
        mutex_unlock(&ls->ls_clear_proc_locks);
        unlock_recovery(ls);
 }
+
index 59012b0..f40817b 100644 (file)
@@ -236,7 +236,7 @@ static int dlm_scand(void *data)
        while (!kthread_should_stop()) {
                list_for_each_entry(ls, &lslist, ls_list)
                        dlm_scan_rsbs(ls);
-               schedule_timeout_interruptible(dlm_config.scan_secs * HZ);
+               schedule_timeout_interruptible(dlm_config.ci_scan_secs * HZ);
        }
        return 0;
 }
@@ -422,7 +422,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
        ls->ls_count = 0;
        ls->ls_flags = 0;
 
-       size = dlm_config.rsbtbl_size;
+       size = dlm_config.ci_rsbtbl_size;
        ls->ls_rsbtbl_size = size;
 
        ls->ls_rsbtbl = kmalloc(sizeof(struct dlm_rsbtable) * size, GFP_KERNEL);
@@ -434,7 +434,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
                rwlock_init(&ls->ls_rsbtbl[i].lock);
        }
 
-       size = dlm_config.lkbtbl_size;
+       size = dlm_config.ci_lkbtbl_size;
        ls->ls_lkbtbl_size = size;
 
        ls->ls_lkbtbl = kmalloc(sizeof(struct dlm_lkbtable) * size, GFP_KERNEL);
@@ -446,7 +446,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
                ls->ls_lkbtbl[i].counter = 1;
        }
 
-       size = dlm_config.dirtbl_size;
+       size = dlm_config.ci_dirtbl_size;
        ls->ls_dirtbl_size = size;
 
        ls->ls_dirtbl = kmalloc(sizeof(struct dlm_dirtable) * size, GFP_KERNEL);
@@ -489,7 +489,7 @@ static int new_lockspace(char *name, int namelen, void **lockspace,
        mutex_init(&ls->ls_requestqueue_mutex);
        mutex_init(&ls->ls_clear_proc_locks);
 
-       ls->ls_recover_buf = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
+       ls->ls_recover_buf = kmalloc(dlm_config.ci_buffer_size, GFP_KERNEL);
        if (!ls->ls_recover_buf)
                goto out_dirfree;
 
index fe158d7..dc83a9d 100644 (file)
@@ -72,6 +72,8 @@ struct nodeinfo {
        struct list_head        writequeue; /* outgoing writequeue_entries */
        spinlock_t              writequeue_lock;
        int                     nodeid;
+       struct work_struct      swork; /* Send workqueue */
+       struct work_struct      lwork; /* Locking workqueue */
 };
 
 static DEFINE_IDR(nodeinfo_idr);
@@ -96,6 +98,7 @@ struct connection {
        atomic_t                waiting_requests;
        struct cbuf             cb;
        int                     eagain_flag;
+       struct work_struct      work; /* Send workqueue */
 };
 
 /* An entry waiting to be sent */
@@ -137,19 +140,23 @@ static void cbuf_eat(struct cbuf *cb, int n)
 static LIST_HEAD(write_nodes);
 static DEFINE_SPINLOCK(write_nodes_lock);
 
+
 /* Maximum number of incoming messages to process before
  * doing a schedule()
  */
 #define MAX_RX_MSG_COUNT 25
 
-/* Manage daemons */
-static struct task_struct *recv_task;
-static struct task_struct *send_task;
-static DECLARE_WAIT_QUEUE_HEAD(lowcomms_recv_wait);
+/* Work queues */
+static struct workqueue_struct *recv_workqueue;
+static struct workqueue_struct *send_workqueue;
+static struct workqueue_struct *lock_workqueue;
 
 /* The SCTP connection */
 static struct connection sctp_con;
 
+static void process_send_sockets(struct work_struct *work);
+static void process_recv_sockets(struct work_struct *work);
+static void process_lock_request(struct work_struct *work);
 
 static int nodeid_to_addr(int nodeid, struct sockaddr *retaddr)
 {
@@ -222,6 +229,8 @@ static struct nodeinfo *nodeid2nodeinfo(int nodeid, gfp_t alloc)
        spin_lock_init(&ni->lock);
        INIT_LIST_HEAD(&ni->writequeue);
        spin_lock_init(&ni->writequeue_lock);
+       INIT_WORK(&ni->lwork, process_lock_request);
+       INIT_WORK(&ni->swork, process_send_sockets);
        ni->nodeid = nodeid;
 
        if (nodeid > max_nodeid)
@@ -249,11 +258,8 @@ static struct nodeinfo *assoc2nodeinfo(sctp_assoc_t assoc)
 /* Data or notification available on socket */
 static void lowcomms_data_ready(struct sock *sk, int count_unused)
 {
-       atomic_inc(&sctp_con.waiting_requests);
        if (test_and_set_bit(CF_READ_PENDING, &sctp_con.flags))
-               return;
-
-       wake_up_interruptible(&lowcomms_recv_wait);
+               queue_work(recv_workqueue, &sctp_con.work);
 }
 
 
@@ -361,10 +367,10 @@ static void init_failed(void)
                                spin_lock_bh(&write_nodes_lock);
                                list_add_tail(&ni->write_list, &write_nodes);
                                spin_unlock_bh(&write_nodes_lock);
+                               queue_work(send_workqueue, &ni->swork);
                        }
                }
        }
-       wake_up_process(send_task);
 }
 
 /* Something happened to an association */
@@ -446,8 +452,8 @@ static void process_sctp_notification(struct msghdr *msg, char *buf)
                                spin_lock_bh(&write_nodes_lock);
                                list_add_tail(&ni->write_list, &write_nodes);
                                spin_unlock_bh(&write_nodes_lock);
+                               queue_work(send_workqueue, &ni->swork);
                        }
-                       wake_up_process(send_task);
                }
                break;
 
@@ -580,8 +586,8 @@ static int receive_from_sock(void)
                                spin_lock_bh(&write_nodes_lock);
                                list_add_tail(&ni->write_list, &write_nodes);
                                spin_unlock_bh(&write_nodes_lock);
+                               queue_work(send_workqueue, &ni->swork);
                        }
-                       wake_up_process(send_task);
                }
        }
 
@@ -590,6 +596,7 @@ static int receive_from_sock(void)
                return 0;
 
        cbuf_add(&sctp_con.cb, ret);
+       // PJC: TODO: Add to node's workqueue....can we ??
        ret = dlm_process_incoming_buffer(cpu_to_le32(sinfo->sinfo_ppid),
                                          page_address(sctp_con.rx_page),
                                          sctp_con.cb.base, sctp_con.cb.len,
@@ -635,7 +642,7 @@ static int add_bind_addr(struct sockaddr_storage *addr, int addr_len, int num)
 
        if (result < 0)
                log_print("Can't bind to port %d addr number %d",
-                         dlm_config.tcp_port, num);
+                         dlm_config.ci_tcp_port, num);
 
        return result;
 }
@@ -711,7 +718,7 @@ static int init_sock(void)
        /* Bind to all interfaces. */
        for (i = 0; i < dlm_local_count; i++) {
                memcpy(&localaddr, dlm_local_addr[i], sizeof(localaddr));
-               make_sockaddr(&localaddr, dlm_config.tcp_port, &addr_len);
+               make_sockaddr(&localaddr, dlm_config.ci_tcp_port, &addr_len);
 
                result = add_bind_addr(&localaddr, addr_len, num);
                if (result)
@@ -820,7 +827,8 @@ void dlm_lowcomms_commit_buffer(void *arg)
                spin_lock_bh(&write_nodes_lock);
                list_add_tail(&ni->write_list, &write_nodes);
                spin_unlock_bh(&write_nodes_lock);
-               wake_up_process(send_task);
+
+               queue_work(send_workqueue, &ni->swork);
        }
        return;
 
@@ -863,7 +871,7 @@ static void initiate_association(int nodeid)
                return;
        }
 
-       make_sockaddr(&rem_addr, dlm_config.tcp_port, &addrlen);
+       make_sockaddr(&rem_addr, dlm_config.ci_tcp_port, &addrlen);
 
        outmessage.msg_name = &rem_addr;
        outmessage.msg_namelen = addrlen;
@@ -1088,101 +1096,75 @@ int dlm_lowcomms_close(int nodeid)
        return 0;
 }
 
-static int write_list_empty(void)
+// PJC: The work queue function for receiving.
+static void process_recv_sockets(struct work_struct *work)
 {
-       int status;
-
-       spin_lock_bh(&write_nodes_lock);
-       status = list_empty(&write_nodes);
-       spin_unlock_bh(&write_nodes_lock);
-
-       return status;
-}
-
-static int dlm_recvd(void *data)
-{
-       DECLARE_WAITQUEUE(wait, current);
-
-       while (!kthread_should_stop()) {
+       if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) {
+               int ret;
                int count = 0;
 
-               set_current_state(TASK_INTERRUPTIBLE);
-               add_wait_queue(&lowcomms_recv_wait, &wait);
-               if (!test_bit(CF_READ_PENDING, &sctp_con.flags))
-                       cond_resched();
-               remove_wait_queue(&lowcomms_recv_wait, &wait);
-               set_current_state(TASK_RUNNING);
-
-               if (test_and_clear_bit(CF_READ_PENDING, &sctp_con.flags)) {
-                       int ret;
-
-                       do {
-                               ret = receive_from_sock();
+               do {
+                       ret = receive_from_sock();
 
-                               /* Don't starve out everyone else */
-                               if (++count >= MAX_RX_MSG_COUNT) {
-                                       cond_resched();
-                                       count = 0;
-                               }
-                       } while (!kthread_should_stop() && ret >=0);
-               }
-               cond_resched();
+                       /* Don't starve out everyone else */
+                       if (++count >= MAX_RX_MSG_COUNT) {
+                               cond_resched();
+                               count = 0;
+                       }
+               } while (!kthread_should_stop() && ret >=0);
        }
-
-       return 0;
+       cond_resched();
 }
 
-static int dlm_sendd(void *data)
+// PJC: the work queue function for sending
+static void process_send_sockets(struct work_struct *work)
 {
-       DECLARE_WAITQUEUE(wait, current);
-
-       add_wait_queue(sctp_con.sock->sk->sk_sleep, &wait);
-
-       while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (write_list_empty())
-                       cond_resched();
-               set_current_state(TASK_RUNNING);
-
-               if (sctp_con.eagain_flag) {
-                       sctp_con.eagain_flag = 0;
-                       refill_write_queue();
-               }
-               process_output_queue();
+       if (sctp_con.eagain_flag) {
+               sctp_con.eagain_flag = 0;
+               refill_write_queue();
        }
+       process_output_queue();
+}
 
-       remove_wait_queue(sctp_con.sock->sk->sk_sleep, &wait);
-
-       return 0;
+// PJC: Process lock requests from a particular node.
+// TODO: can we optimise this out on UP ??
+static void process_lock_request(struct work_struct *work)
+{
 }
 
 static void daemons_stop(void)
 {
-       kthread_stop(recv_task);
-       kthread_stop(send_task);
+       destroy_workqueue(recv_workqueue);
+       destroy_workqueue(send_workqueue);
+       destroy_workqueue(lock_workqueue);
 }
 
 static int daemons_start(void)
 {
-       struct task_struct *p;
        int error;
+       recv_workqueue = create_workqueue("dlm_recv");
+       error = IS_ERR(recv_workqueue);
+       if (error) {
+               log_print("can't start dlm_recv %d", error);
+               return error;
+       }
 
-       p = kthread_run(dlm_recvd, NULL, "dlm_recvd");
-       error = IS_ERR(p);
+       send_workqueue = create_singlethread_workqueue("dlm_send");
+       error = IS_ERR(send_workqueue);
        if (error) {
-               log_print("can't start dlm_recvd %d", error);
+               log_print("can't start dlm_send %d", error);
+               destroy_workqueue(recv_workqueue);
                return error;
        }
-       recv_task = p;
 
-       p = kthread_run(dlm_sendd, NULL, "dlm_sendd");
-       error = IS_ERR(p);
+       lock_workqueue = create_workqueue("dlm_rlock");
+       error = IS_ERR(lock_workqueue);
        if (error) {
-               log_print("can't start dlm_sendd %d", error);
-               kthread_stop(recv_task);
+               log_print("can't start dlm_rlock %d", error);
+               destroy_workqueue(send_workqueue);
+               destroy_workqueue(recv_workqueue);
                return error;
        }
-       send_task = p;
 
        return 0;
 }
@@ -1194,6 +1176,8 @@ int dlm_lowcomms_start(void)
 {
        int error;
 
+       INIT_WORK(&sctp_con.work, process_recv_sockets);
+
        error = init_sock();
        if (error)
                goto fail_sock;
@@ -1224,4 +1208,3 @@ void dlm_lowcomms_stop(void)
        for (i = 0; i < dlm_local_count; i++)
                kfree(dlm_local_addr[i]);
 }
-
index 9be3a44..f1efd17 100644 (file)
@@ -2,7 +2,7 @@
 *******************************************************************************
 **
 **  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
-**  Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
+**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
 **
 **  This copyrighted material is made available to anyone wishing to use,
 **  modify, copy, or redistribute it subject to the terms and conditions
@@ -96,10 +96,7 @@ static bool cbuf_empty(struct cbuf *cb)
 struct connection {
        struct socket *sock;    /* NULL if not connected */
        uint32_t nodeid;        /* So we know who we are in the list */
-       struct rw_semaphore sock_sem; /* Stop connect races */
-       struct list_head read_list;   /* On this list when ready for reading */
-       struct list_head write_list;  /* On this list when ready for writing */
-       struct list_head state_list;  /* On this list when ready to connect */
+       struct mutex sock_mutex;
        unsigned long flags;    /* bit 1,2 = We are on the read/write lists */
 #define CF_READ_PENDING 1
 #define CF_WRITE_PENDING 2
@@ -112,9 +109,10 @@ struct connection {
        struct page *rx_page;
        struct cbuf cb;
        int retries;
-       atomic_t waiting_requests;
 #define MAX_CONNECT_RETRIES 3
        struct connection *othercon;
+       struct work_struct rwork; /* Receive workqueue */
+       struct work_struct swork; /* Send workqueue */
 };
 #define sock2con(x) ((struct connection *)(x)->sk_user_data)
 
@@ -131,14 +129,9 @@ struct writequeue_entry {
 
 static struct sockaddr_storage dlm_local_addr;
 
-/* Manage daemons */
-static struct task_struct *recv_task;
-static struct task_struct *send_task;
-
-static wait_queue_t lowcomms_send_waitq_head;
-static DECLARE_WAIT_QUEUE_HEAD(lowcomms_send_waitq);
-static wait_queue_t lowcomms_recv_waitq_head;
-static DECLARE_WAIT_QUEUE_HEAD(lowcomms_recv_waitq);
+/* Work queues */
+static struct workqueue_struct *recv_workqueue;
+static struct workqueue_struct *send_workqueue;
 
 /* An array of pointers to connections, indexed by NODEID */
 static struct connection **connections;
@@ -146,17 +139,8 @@ static DECLARE_MUTEX(connections_lock);
 static struct kmem_cache *con_cache;
 static int conn_array_size;
 
-/* List of sockets that have reads pending */
-static LIST_HEAD(read_sockets);
-static DEFINE_SPINLOCK(read_sockets_lock);
-
-/* List of sockets which have writes pending */
-static LIST_HEAD(write_sockets);
-static DEFINE_SPINLOCK(write_sockets_lock);
-
-/* List of sockets which have connects pending */
-static LIST_HEAD(state_sockets);
-static DEFINE_SPINLOCK(state_sockets_lock);
+static void process_recv_sockets(struct work_struct *work);
+static void process_send_sockets(struct work_struct *work);
 
 static struct connection *nodeid2con(int nodeid, gfp_t allocation)
 {
@@ -186,9 +170,11 @@ static struct connection *nodeid2con(int nodeid, gfp_t allocation)
                        goto finish;
 
                con->nodeid = nodeid;
-               init_rwsem(&con->sock_sem);
+               mutex_init(&con->sock_mutex);
                INIT_LIST_HEAD(&con->writequeue);
                spin_lock_init(&con->writequeue_lock);
+               INIT_WORK(&con->swork, process_send_sockets);
+               INIT_WORK(&con->rwork, process_recv_sockets);
 
                connections[nodeid] = con;
        }
@@ -203,41 +189,22 @@ static void lowcomms_data_ready(struct sock *sk, int count_unused)
 {
        struct connection *con = sock2con(sk);
 
-       atomic_inc(&con->waiting_requests);
-       if (test_and_set_bit(CF_READ_PENDING, &con->flags))
-               return;
-
-       spin_lock_bh(&read_sockets_lock);
-       list_add_tail(&con->read_list, &read_sockets);
-       spin_unlock_bh(&read_sockets_lock);
-
-       wake_up_interruptible(&lowcomms_recv_waitq);
+       if (!test_and_set_bit(CF_READ_PENDING, &con->flags))
+               queue_work(recv_workqueue, &con->rwork);
 }
 
 static void lowcomms_write_space(struct sock *sk)
 {
        struct connection *con = sock2con(sk);
 
-       if (test_and_set_bit(CF_WRITE_PENDING, &con->flags))
-               return;
-
-       spin_lock_bh(&write_sockets_lock);
-       list_add_tail(&con->write_list, &write_sockets);
-       spin_unlock_bh(&write_sockets_lock);
-
-       wake_up_interruptible(&lowcomms_send_waitq);
+       if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags))
+               queue_work(send_workqueue, &con->swork);
 }
 
 static inline void lowcomms_connect_sock(struct connection *con)
 {
-       if (test_and_set_bit(CF_CONNECT_PENDING, &con->flags))
-               return;
-
-       spin_lock_bh(&state_sockets_lock);
-       list_add_tail(&con->state_list, &state_sockets);
-       spin_unlock_bh(&state_sockets_lock);
-
-       wake_up_interruptible(&lowcomms_send_waitq);
+       if (!test_and_set_bit(CF_CONNECT_PENDING, &con->flags))
+               queue_work(send_workqueue, &con->swork);
 }
 
 static void lowcomms_state_change(struct sock *sk)
@@ -279,7 +246,7 @@ static void make_sockaddr(struct sockaddr_storage *saddr, uint16_t port,
 /* Close a remote connection and tidy up */
 static void close_connection(struct connection *con, bool and_other)
 {
-       down_write(&con->sock_sem);
+       mutex_lock(&con->sock_mutex);
 
        if (con->sock) {
                sock_release(con->sock);
@@ -294,7 +261,7 @@ static void close_connection(struct connection *con, bool and_other)
                con->rx_page = NULL;
        }
        con->retries = 0;
-       up_write(&con->sock_sem);
+       mutex_unlock(&con->sock_mutex);
 }
 
 /* Data received from remote end */
@@ -308,10 +275,13 @@ static int receive_from_sock(struct connection *con)
        int r;
        int call_again_soon = 0;
 
-       down_read(&con->sock_sem);
+       mutex_lock(&con->sock_mutex);
+
+       if (con->sock == NULL) {
+               ret = -EAGAIN;
+               goto out_close;
+       }
 
-       if (con->sock == NULL)
-               goto out;
        if (con->rx_page == NULL) {
                /*
                 * This doesn't need to be atomic, but I think it should
@@ -359,6 +329,9 @@ static int receive_from_sock(struct connection *con)
 
        if (ret <= 0)
                goto out_close;
+       if (ret == -EAGAIN)
+               goto out_resched;
+
        if (ret == len)
                call_again_soon = 1;
        cbuf_add(&con->cb, ret);
@@ -381,24 +354,26 @@ static int receive_from_sock(struct connection *con)
                con->rx_page = NULL;
        }
 
-out:
        if (call_again_soon)
                goto out_resched;
-       up_read(&con->sock_sem);
+       mutex_unlock(&con->sock_mutex);
        return 0;
 
 out_resched:
-       lowcomms_data_ready(con->sock->sk, 0);
-       up_read(&con->sock_sem);
-       cond_resched();
-       return 0;
+       if (!test_and_set_bit(CF_READ_PENDING, &con->flags))
+               queue_work(recv_workqueue, &con->rwork);
+       mutex_unlock(&con->sock_mutex);
+       return -EAGAIN;
 
 out_close:
-       up_read(&con->sock_sem);
+       mutex_unlock(&con->sock_mutex);
        if (ret != -EAGAIN && !test_bit(CF_IS_OTHERCON, &con->flags)) {
                close_connection(con, false);
                /* Reconnect when there is something to send */
        }
+       /* Don't return success if we really got EOF */
+       if (ret == 0)
+               ret = -EAGAIN;
 
        return ret;
 }
@@ -412,6 +387,7 @@ static int accept_from_sock(struct connection *con)
        int len;
        int nodeid;
        struct connection *newcon;
+       struct connection *addcon;
 
        memset(&peeraddr, 0, sizeof(peeraddr));
        result = sock_create_kern(dlm_local_addr.ss_family, SOCK_STREAM,
@@ -419,7 +395,7 @@ static int accept_from_sock(struct connection *con)
        if (result < 0)
                return -ENOMEM;
 
-       down_read(&con->sock_sem);
+       mutex_lock_nested(&con->sock_mutex, 0);
 
        result = -ENOTCONN;
        if (con->sock == NULL)
@@ -445,7 +421,7 @@ static int accept_from_sock(struct connection *con)
        if (dlm_addr_to_nodeid(&peeraddr, &nodeid)) {
                printk("dlm: connect from non cluster node\n");
                sock_release(newsock);
-               up_read(&con->sock_sem);
+               mutex_unlock(&con->sock_mutex);
                return -1;
        }
 
@@ -462,7 +438,7 @@ static int accept_from_sock(struct connection *con)
                result = -ENOMEM;
                goto accept_err;
        }
-       down_write(&newcon->sock_sem);
+       mutex_lock_nested(&newcon->sock_mutex, 1);
        if (newcon->sock) {
                struct connection *othercon = newcon->othercon;
 
@@ -470,41 +446,45 @@ static int accept_from_sock(struct connection *con)
                        othercon = kmem_cache_zalloc(con_cache, GFP_KERNEL);
                        if (!othercon) {
                                printk("dlm: failed to allocate incoming socket\n");
-                               up_write(&newcon->sock_sem);
+                               mutex_unlock(&newcon->sock_mutex);
                                result = -ENOMEM;
                                goto accept_err;
                        }
                        othercon->nodeid = nodeid;
                        othercon->rx_action = receive_from_sock;
-                       init_rwsem(&othercon->sock_sem);
+                       mutex_init(&othercon->sock_mutex);
+                       INIT_WORK(&othercon->swork, process_send_sockets);
+                       INIT_WORK(&othercon->rwork, process_recv_sockets);
                        set_bit(CF_IS_OTHERCON, &othercon->flags);
                        newcon->othercon = othercon;
                }
                othercon->sock = newsock;
                newsock->sk->sk_user_data = othercon;
                add_sock(newsock, othercon);
+               addcon = othercon;
        }
        else {
                newsock->sk->sk_user_data = newcon;
                newcon->rx_action = receive_from_sock;
                add_sock(newsock, newcon);
-
+               addcon = newcon;
        }
 
-       up_write(&newcon->sock_sem);
+       mutex_unlock(&newcon->sock_mutex);
 
        /*
         * Add it to the active queue in case we got data
         * beween processing the accept adding the socket
         * to the read_sockets list
         */
-       lowcomms_data_ready(newsock->sk, 0);
-       up_read(&con->sock_sem);
+       if (!test_and_set_bit(CF_READ_PENDING, &addcon->flags))
+               queue_work(recv_workqueue, &addcon->rwork);
+       mutex_unlock(&con->sock_mutex);
 
        return 0;
 
 accept_err:
-       up_read(&con->sock_sem);
+       mutex_unlock(&con->sock_mutex);
        sock_release(newsock);
 
        if (result != -EAGAIN)
@@ -525,7 +505,7 @@ static void connect_to_sock(struct connection *con)
                return;
        }
 
-       down_write(&con->sock_sem);
+       mutex_lock(&con->sock_mutex);
        if (con->retries++ > MAX_CONNECT_RETRIES)
                goto out;
 
@@ -548,7 +528,7 @@ static void connect_to_sock(struct connection *con)
        sock->sk->sk_user_data = con;
        con->rx_action = receive_from_sock;
 
-       make_sockaddr(&saddr, dlm_config.tcp_port, &addr_len);
+       make_sockaddr(&saddr, dlm_config.ci_tcp_port, &addr_len);
 
        add_sock(sock, con);
 
@@ -577,7 +557,7 @@ out_err:
                result = 0;
        }
 out:
-       up_write(&con->sock_sem);
+       mutex_unlock(&con->sock_mutex);
        return;
 }
 
@@ -616,10 +596,10 @@ static struct socket *create_listen_sock(struct connection *con,
        con->sock = sock;
 
        /* Bind to our port */
-       make_sockaddr(saddr, dlm_config.tcp_port, &addr_len);
+       make_sockaddr(saddr, dlm_config.ci_tcp_port, &addr_len);
        result = sock->ops->bind(sock, (struct sockaddr *) saddr, addr_len);
        if (result < 0) {
-               printk("dlm: Can't bind to port %d\n", dlm_config.tcp_port);
+               printk("dlm: Can't bind to port %d\n", dlm_config.ci_tcp_port);
                sock_release(sock);
                sock = NULL;
                con->sock = NULL;
@@ -638,7 +618,7 @@ static struct socket *create_listen_sock(struct connection *con,
 
        result = sock->ops->listen(sock, 5);
        if (result < 0) {
-               printk("dlm: Can't listen on port %d\n", dlm_config.tcp_port);
+               printk("dlm: Can't listen on port %d\n", dlm_config.ci_tcp_port);
                sock_release(sock);
                sock = NULL;
                goto create_out;
@@ -709,6 +689,7 @@ void *dlm_lowcomms_get_buffer(int nodeid, int len,
        if (!con)
                return NULL;
 
+       spin_lock(&con->writequeue_lock);
        e = list_entry(con->writequeue.prev, struct writequeue_entry, list);
        if ((&e->list == &con->writequeue) ||
            (PAGE_CACHE_SIZE - e->end < len)) {
@@ -747,6 +728,7 @@ void dlm_lowcomms_commit_buffer(void *mh)
        struct connection *con = e->con;
        int users;
 
+       spin_lock(&con->writequeue_lock);
        users = --e->users;
        if (users)
                goto out;
@@ -754,12 +736,8 @@ void dlm_lowcomms_commit_buffer(void *mh)
        kunmap(e->page);
        spin_unlock(&con->writequeue_lock);
 
-       if (test_and_set_bit(CF_WRITE_PENDING, &con->flags) == 0) {
-               spin_lock_bh(&write_sockets_lock);
-               list_add_tail(&con->write_list, &write_sockets);
-               spin_unlock_bh(&write_sockets_lock);
-
-               wake_up_interruptible(&lowcomms_send_waitq);
+       if (!test_and_set_bit(CF_WRITE_PENDING, &con->flags)) {
+               queue_work(send_workqueue, &con->swork);
        }
        return;
 
@@ -783,7 +761,7 @@ static void send_to_sock(struct connection *con)
        struct writequeue_entry *e;
        int len, offset;
 
-       down_read(&con->sock_sem);
+       mutex_lock(&con->sock_mutex);
        if (con->sock == NULL)
                goto out_connect;
 
@@ -800,6 +778,7 @@ static void send_to_sock(struct connection *con)
                offset = e->offset;
                BUG_ON(len == 0 && e->users == 0);
                spin_unlock(&con->writequeue_lock);
+               kmap(e->page);
 
                ret = 0;
                if (len) {
@@ -828,18 +807,18 @@ static void send_to_sock(struct connection *con)
        }
        spin_unlock(&con->writequeue_lock);
 out:
-       up_read(&con->sock_sem);
+       mutex_unlock(&con->sock_mutex);
        return;
 
 send_error:
-       up_read(&con->sock_sem);
+       mutex_unlock(&con->sock_mutex);
        close_connection(con, false);
        lowcomms_connect_sock(con);
        return;
 
 out_connect:
-       up_read(&con->sock_sem);
-       lowcomms_connect_sock(con);
+       mutex_unlock(&con->sock_mutex);
+       connect_to_sock(con);
        return;
 }
 
@@ -872,7 +851,6 @@ int dlm_lowcomms_close(int nodeid)
        if (con) {
                clean_one_writequeue(con);
                close_connection(con, true);
-               atomic_set(&con->waiting_requests, 0);
        }
        return 0;
 
@@ -880,102 +858,29 @@ out:
        return -1;
 }
 
-/* API send message call, may queue the request */
-/* N.B. This is the old interface - use the new one for new calls */
-int lowcomms_send_message(int nodeid, char *buf, int len, gfp_t allocation)
-{
-       struct writequeue_entry *e;
-       char *b;
-
-       e = dlm_lowcomms_get_buffer(nodeid, len, allocation, &b);
-       if (e) {
-               memcpy(b, buf, len);
-               dlm_lowcomms_commit_buffer(e);
-               return 0;
-       }
-       return -ENOBUFS;
-}
-
 /* Look for activity on active sockets */
-static void process_sockets(void)
+static void process_recv_sockets(struct work_struct *work)
 {
-       struct list_head *list;
-       struct list_head *temp;
-       int count = 0;
-
-       spin_lock_bh(&read_sockets_lock);
-       list_for_each_safe(list, temp, &read_sockets) {
+       struct connection *con = container_of(work, struct connection, rwork);
+       int err;
 
-               struct connection *con =
-                       list_entry(list, struct connection, read_list);
-               list_del(&con->read_list);
-               clear_bit(CF_READ_PENDING, &con->flags);
-
-               spin_unlock_bh(&read_sockets_lock);
-
-               /* This can reach zero if we are processing requests
-                * as they come in.
-                */
-               if (atomic_read(&con->waiting_requests) == 0) {
-                       spin_lock_bh(&read_sockets_lock);
-                       continue;
-               }
-
-               do {
-                       con->rx_action(con);
-
-                       /* Don't starve out everyone else */
-                       if (++count >= MAX_RX_MSG_COUNT) {
-                               cond_resched();
-                               count = 0;
-                       }
-
-               } while (!atomic_dec_and_test(&con->waiting_requests) &&
-                        !kthread_should_stop());
-
-               spin_lock_bh(&read_sockets_lock);
-       }
-       spin_unlock_bh(&read_sockets_lock);
+       clear_bit(CF_READ_PENDING, &con->flags);
+       do {
+               err = con->rx_action(con);
+       } while (!err);
 }
 
-/* Try to send any messages that are pending
- */
-static void process_output_queue(void)
-{
-       struct list_head *list;
-       struct list_head *temp;
-
-       spin_lock_bh(&write_sockets_lock);
-       list_for_each_safe(list, temp, &write_sockets) {
-               struct connection *con =
-                       list_entry(list, struct connection, write_list);
-               clear_bit(CF_WRITE_PENDING, &con->flags);
-               list_del(&con->write_list);
-
-               spin_unlock_bh(&write_sockets_lock);
-               send_to_sock(con);
-               spin_lock_bh(&write_sockets_lock);
-       }
-       spin_unlock_bh(&write_sockets_lock);
-}
 
-static void process_state_queue(void)
+static void process_send_sockets(struct work_struct *work)
 {
-       struct list_head *list;
-       struct list_head *temp;
-
-       spin_lock_bh(&state_sockets_lock);
-       list_for_each_safe(list, temp, &state_sockets) {
-               struct connection *con =
-                       list_entry(list, struct connection, state_list);
-               list_del(&con->state_list);
-               clear_bit(CF_CONNECT_PENDING, &con->flags);
-               spin_unlock_bh(&state_sockets_lock);
+       struct connection *con = container_of(work, struct connection, swork);
 
+       if (test_and_clear_bit(CF_CONNECT_PENDING, &con->flags)) {
                connect_to_sock(con);
-               spin_lock_bh(&state_sockets_lock);
        }
-       spin_unlock_bh(&state_sockets_lock);
+
+       clear_bit(CF_WRITE_PENDING, &con->flags);
+       send_to_sock(con);
 }
 
 
@@ -992,109 +897,33 @@ static void clean_writequeues(void)
        }
 }
 
-static int read_list_empty(void)
+static void work_stop(void)
 {
-       int status;
-
-       spin_lock_bh(&read_sockets_lock);
-       status = list_empty(&read_sockets);
-       spin_unlock_bh(&read_sockets_lock);
-
-       return status;
-}
-
-/* DLM Transport comms receive daemon */
-static int dlm_recvd(void *data)
-{
-       init_waitqueue_entry(&lowcomms_recv_waitq_head, current);
-       add_wait_queue(&lowcomms_recv_waitq, &lowcomms_recv_waitq_head);
-
-       while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (read_list_empty())
-                       cond_resched();
-               set_current_state(TASK_RUNNING);
-
-               process_sockets();
-       }
-
-       return 0;
+       destroy_workqueue(recv_workqueue);
+       destroy_workqueue(send_workqueue);
 }
 
-static int write_and_state_lists_empty(void)
+static int work_start(void)
 {
-       int status;
-
-       spin_lock_bh(&write_sockets_lock);
-       status = list_empty(&write_sockets);
-       spin_unlock_bh(&write_sockets_lock);
-
-       spin_lock_bh(&state_sockets_lock);
-       if (list_empty(&state_sockets) == 0)
-               status = 0;
-       spin_unlock_bh(&state_sockets_lock);
-
-       return status;
-}
-
-/* DLM Transport send daemon */
-static int dlm_sendd(void *data)
-{
-       init_waitqueue_entry(&lowcomms_send_waitq_head, current);
-       add_wait_queue(&lowcomms_send_waitq, &lowcomms_send_waitq_head);
-
-       while (!kthread_should_stop()) {
-               set_current_state(TASK_INTERRUPTIBLE);
-               if (write_and_state_lists_empty())
-                       cond_resched();
-               set_current_state(TASK_RUNNING);
-
-               process_state_queue();
-               process_output_queue();
-       }
-
-       return 0;
-}
-
-static void daemons_stop(void)
-{
-       kthread_stop(recv_task);
-       kthread_stop(send_task);
-}
-
-static int daemons_start(void)
-{
-       struct task_struct *p;
        int error;
-
-       p = kthread_run(dlm_recvd, NULL, "dlm_recvd");
-       error = IS_ERR(p);
+       recv_workqueue = create_workqueue("dlm_recv");
+       error = IS_ERR(recv_workqueue);
        if (error) {
-               log_print("can't start dlm_recvd %d", error);
+               log_print("can't start dlm_recv %d", error);
                return error;
        }
-       recv_task = p;
 
-       p = kthread_run(dlm_sendd, NULL, "dlm_sendd");
-       error = IS_ERR(p);
+       send_workqueue = create_singlethread_workqueue("dlm_send");
+       error = IS_ERR(send_workqueue);
        if (error) {
-               log_print("can't start dlm_sendd %d", error);
-               kthread_stop(recv_task);
+               log_print("can't start dlm_send %d", error);
+               destroy_workqueue(recv_workqueue);
                return error;
        }
-       send_task = p;
 
        return 0;
 }
 
-/*
- * Return the largest buffer size we can cope with.
- */
-int lowcomms_max_buffer_size(void)
-{
-       return PAGE_CACHE_SIZE;
-}
-
 void dlm_lowcomms_stop(void)
 {
        int i;
@@ -1107,7 +936,7 @@ void dlm_lowcomms_stop(void)
                        connections[i]->flags |= 0xFF;
        }
 
-       daemons_stop();
+       work_stop();
        clean_writequeues();
 
        for (i = 0; i < conn_array_size; i++) {
@@ -1159,7 +988,7 @@ int dlm_lowcomms_start(void)
        if (error)
                goto fail_unlisten;
 
-       error = daemons_start();
+       error = work_start();
        if (error)
                goto fail_unlisten;
 
index c9b1c3d..a5126e0 100644 (file)
@@ -82,7 +82,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base,
                if (msglen < sizeof(struct dlm_header))
                        break;
                err = -E2BIG;
-               if (msglen > dlm_config.buffer_size) {
+               if (msglen > dlm_config.ci_buffer_size) {
                        log_print("message size %d from %d too big, buf len %d",
                                  msglen, nodeid, len);
                        break;
@@ -103,7 +103,7 @@ int dlm_process_incoming_buffer(int nodeid, const void *base,
 
                if (msglen > sizeof(__tmp) &&
                    msg == (struct dlm_header *) __tmp) {
-                       msg = kmalloc(dlm_config.buffer_size, GFP_KERNEL);
+                       msg = kmalloc(dlm_config.ci_buffer_size, GFP_KERNEL);
                        if (msg == NULL)
                                return ret;
                }
index 4cc31be..6bfbd61 100644 (file)
@@ -56,6 +56,10 @@ static int create_rcom(struct dlm_ls *ls, int to_nodeid, int type, int len,
 
        rc->rc_type = type;
 
+       spin_lock(&ls->ls_recover_lock);
+       rc->rc_seq = ls->ls_recover_seq;
+       spin_unlock(&ls->ls_recover_lock);
+
        *mh_ret = mh;
        *rc_ret = rc;
        return 0;
@@ -78,8 +82,17 @@ static void make_config(struct dlm_ls *ls, struct rcom_config *rf)
        rf->rf_lsflags = ls->ls_exflags;
 }
 
-static int check_config(struct dlm_ls *ls, struct rcom_config *rf, int nodeid)
+static int check_config(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid)
 {
+       struct rcom_config *rf = (struct rcom_config *) rc->rc_buf;
+
+       if ((rc->rc_header.h_version & 0xFFFF0000) != DLM_HEADER_MAJOR) {
+               log_error(ls, "version mismatch: %x nodeid %d: %x",
+                         DLM_HEADER_MAJOR | DLM_HEADER_MINOR, nodeid,
+                         rc->rc_header.h_version);
+               return -EINVAL;
+       }
+
        if (rf->rf_lvblen != ls->ls_lvblen ||
            rf->rf_lsflags != ls->ls_exflags) {
                log_error(ls, "config mismatch: %d,%x nodeid %d: %d,%x",
@@ -125,7 +138,7 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid)
                goto out;
 
        allow_sync_reply(ls, &rc->rc_id);
-       memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
+       memset(ls->ls_recover_buf, 0, dlm_config.ci_buffer_size);
 
        send_rcom(ls, mh, rc);
 
@@ -141,8 +154,7 @@ int dlm_rcom_status(struct dlm_ls *ls, int nodeid)
                log_debug(ls, "remote node %d not ready", nodeid);
                rc->rc_result = 0;
        } else
-               error = check_config(ls, (struct rcom_config *) rc->rc_buf,
-                                    nodeid);
+               error = check_config(ls, rc, nodeid);
        /* the caller looks at rc_result for the remote recovery status */
  out:
        return error;
@@ -159,6 +171,7 @@ static void receive_rcom_status(struct dlm_ls *ls, struct dlm_rcom *rc_in)
        if (error)
                return;
        rc->rc_id = rc_in->rc_id;
+       rc->rc_seq_reply = rc_in->rc_seq;
        rc->rc_result = dlm_recover_status(ls);
        make_config(ls, (struct rcom_config *) rc->rc_buf);
 
@@ -200,7 +213,7 @@ int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len)
        if (nodeid == dlm_our_nodeid()) {
                dlm_copy_master_names(ls, last_name, last_len,
                                      ls->ls_recover_buf + len,
-                                     dlm_config.buffer_size - len, nodeid);
+                                     dlm_config.ci_buffer_size - len, nodeid);
                goto out;
        }
 
@@ -210,7 +223,7 @@ int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name, int last_len)
        memcpy(rc->rc_buf, last_name, last_len);
 
        allow_sync_reply(ls, &rc->rc_id);
-       memset(ls->ls_recover_buf, 0, dlm_config.buffer_size);
+       memset(ls->ls_recover_buf, 0, dlm_config.ci_buffer_size);
 
        send_rcom(ls, mh, rc);
 
@@ -224,30 +237,17 @@ static void receive_rcom_names(struct dlm_ls *ls, struct dlm_rcom *rc_in)
 {
        struct dlm_rcom *rc;
        struct dlm_mhandle *mh;
-       int error, inlen, outlen;
-       int nodeid = rc_in->rc_header.h_nodeid;
-       uint32_t status = dlm_recover_status(ls);
-
-       /*
-        * We can't run dlm_dir_rebuild_send (which uses ls_nodes) while
-        * dlm_recoverd is running ls_nodes_reconfig (which changes ls_nodes).
-        * It could only happen in rare cases where we get a late NAMES
-        * message from a previous instance of recovery.
-        */
-
-       if (!(status & DLM_RS_NODES)) {
-               log_debug(ls, "ignoring RCOM_NAMES from %u", nodeid);
-               return;
-       }
+       int error, inlen, outlen, nodeid;
 
        nodeid = rc_in->rc_header.h_nodeid;
        inlen = rc_in->rc_header.h_length - sizeof(struct dlm_rcom);
-       outlen = dlm_config.buffer_size - sizeof(struct dlm_rcom);
+       outlen = dlm_config.ci_buffer_size - sizeof(struct dlm_rcom);
 
        error = create_rcom(ls, nodeid, DLM_RCOM_NAMES_REPLY, outlen, &rc, &mh);
        if (error)
                return;
        rc->rc_id = rc_in->rc_id;
+       rc->rc_seq_reply = rc_in->rc_seq;
 
        dlm_copy_master_names(ls, rc_in->rc_buf, inlen, rc->rc_buf, outlen,
                              nodeid);
@@ -294,6 +294,7 @@ static void receive_rcom_lookup(struct dlm_ls *ls, struct dlm_rcom *rc_in)
                ret_nodeid = error;
        rc->rc_result = ret_nodeid;
        rc->rc_id = rc_in->rc_id;
+       rc->rc_seq_reply = rc_in->rc_seq;
 
        send_rcom(ls, mh, rc);
 }
@@ -375,20 +376,13 @@ static void receive_rcom_lock(struct dlm_ls *ls, struct dlm_rcom *rc_in)
 
        memcpy(rc->rc_buf, rc_in->rc_buf, sizeof(struct rcom_lock));
        rc->rc_id = rc_in->rc_id;
+       rc->rc_seq_reply = rc_in->rc_seq;
 
        send_rcom(ls, mh, rc);
 }
 
 static void receive_rcom_lock_reply(struct dlm_ls *ls, struct dlm_rcom *rc_in)
 {
-       uint32_t status = dlm_recover_status(ls);
-
-       if (!(status & DLM_RS_DIR)) {
-               log_debug(ls, "ignoring RCOM_LOCK_REPLY from %u",
-                         rc_in->rc_header.h_nodeid);
-               return;
-       }
-
        dlm_recover_process_copy(ls, rc_in);
 }
 
@@ -415,6 +409,7 @@ static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
 
        rc->rc_type = DLM_RCOM_STATUS_REPLY;
        rc->rc_id = rc_in->rc_id;
+       rc->rc_seq_reply = rc_in->rc_seq;
        rc->rc_result = -ESRCH;
 
        rf = (struct rcom_config *) rc->rc_buf;
@@ -426,6 +421,31 @@ static int send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in)
        return 0;
 }
 
+static int is_old_reply(struct dlm_ls *ls, struct dlm_rcom *rc)
+{
+       uint64_t seq;
+       int rv = 0;
+
+       switch (rc->rc_type) {
+       case DLM_RCOM_STATUS_REPLY:
+       case DLM_RCOM_NAMES_REPLY:
+       case DLM_RCOM_LOOKUP_REPLY:
+       case DLM_RCOM_LOCK_REPLY:
+               spin_lock(&ls->ls_recover_lock);
+               seq = ls->ls_recover_seq;
+               spin_unlock(&ls->ls_recover_lock);
+               if (rc->rc_seq_reply != seq) {
+                       log_debug(ls, "ignoring old reply %x from %d "
+                                     "seq_reply %llx expect %llx",
+                                     rc->rc_type, rc->rc_header.h_nodeid,
+                                     (unsigned long long)rc->rc_seq_reply,
+                                     (unsigned long long)seq);
+                       rv = 1;
+               }
+       }
+       return rv;
+}
+
 /* Called by dlm_recvd; corresponds to dlm_receive_message() but special
    recovery-only comms are sent through here. */
 
@@ -449,11 +469,14 @@ void dlm_receive_rcom(struct dlm_header *hd, int nodeid)
        }
 
        if (dlm_recovery_stopped(ls) && (rc->rc_type != DLM_RCOM_STATUS)) {
-               log_error(ls, "ignoring recovery message %x from %d",
+               log_debug(ls, "ignoring recovery message %x from %d",
                          rc->rc_type, nodeid);
                goto out;
        }
 
+       if (is_old_reply(ls, rc))
+               goto out;
+
        if (nodeid != rc->rc_header.h_nodeid) {
                log_error(ls, "bad rcom nodeid %d from %d",
                          rc->rc_header.h_nodeid, nodeid);
index cf9f683..c2cc769 100644 (file)
@@ -44,7 +44,7 @@
 static void dlm_wait_timer_fn(unsigned long data)
 {
        struct dlm_ls *ls = (struct dlm_ls *) data;
-       mod_timer(&ls->ls_timer, jiffies + (dlm_config.recover_timer * HZ));
+       mod_timer(&ls->ls_timer, jiffies + (dlm_config.ci_recover_timer * HZ));
        wake_up(&ls->ls_wait_general);
 }
 
@@ -55,7 +55,7 @@ int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls))
        init_timer(&ls->ls_timer);
        ls->ls_timer.function = dlm_wait_timer_fn;
        ls->ls_timer.data = (long) ls;
-       ls->ls_timer.expires = jiffies + (dlm_config.recover_timer * HZ);
+       ls->ls_timer.expires = jiffies + (dlm_config.ci_recover_timer * HZ);
        add_timer(&ls->ls_timer);
 
        wait_event(ls->ls_wait_general, testfn(ls) || dlm_recovery_stopped(ls));
@@ -397,7 +397,9 @@ int dlm_recover_masters(struct dlm_ls *ls)
 
                if (dlm_no_directory(ls))
                        count += recover_master_static(r);
-               else if (!is_master(r) && dlm_is_removed(ls, r->res_nodeid)) {
+               else if (!is_master(r) &&
+                        (dlm_is_removed(ls, r->res_nodeid) ||
+                         rsb_flag(r, RSB_NEW_MASTER))) {
                        recover_master(r);
                        count++;
                }
index 650536a..3cb636d 100644 (file)
@@ -77,7 +77,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
        error = dlm_recover_members(ls, rv, &neg);
        if (error) {
-               log_error(ls, "recover_members failed %d", error);
+               log_debug(ls, "recover_members failed %d", error);
                goto fail;
        }
        start = jiffies;
@@ -89,7 +89,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
        error = dlm_recover_directory(ls);
        if (error) {
-               log_error(ls, "recover_directory failed %d", error);
+               log_debug(ls, "recover_directory failed %d", error);
                goto fail;
        }
 
@@ -99,7 +99,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
        error = dlm_recover_directory_wait(ls);
        if (error) {
-               log_error(ls, "recover_directory_wait failed %d", error);
+               log_debug(ls, "recover_directory_wait failed %d", error);
                goto fail;
        }
 
@@ -129,7 +129,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
                error = dlm_recover_masters(ls);
                if (error) {
-                       log_error(ls, "recover_masters failed %d", error);
+                       log_debug(ls, "recover_masters failed %d", error);
                        goto fail;
                }
 
@@ -139,13 +139,13 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
                error = dlm_recover_locks(ls);
                if (error) {
-                       log_error(ls, "recover_locks failed %d", error);
+                       log_debug(ls, "recover_locks failed %d", error);
                        goto fail;
                }
 
                error = dlm_recover_locks_wait(ls);
                if (error) {
-                       log_error(ls, "recover_locks_wait failed %d", error);
+                       log_debug(ls, "recover_locks_wait failed %d", error);
                        goto fail;
                }
 
@@ -166,7 +166,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
                error = dlm_recover_locks_wait(ls);
                if (error) {
-                       log_error(ls, "recover_locks_wait failed %d", error);
+                       log_debug(ls, "recover_locks_wait failed %d", error);
                        goto fail;
                }
        }
@@ -184,7 +184,7 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
        dlm_set_recover_status(ls, DLM_RS_DONE);
        error = dlm_recover_done_wait(ls);
        if (error) {
-               log_error(ls, "recover_done_wait failed %d", error);
+               log_debug(ls, "recover_done_wait failed %d", error);
                goto fail;
        }
 
@@ -192,19 +192,19 @@ static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)
 
        error = enable_locking(ls, rv->seq);
        if (error) {
-               log_error(ls, "enable_locking failed %d", error);
+               log_debug(ls, "enable_locking failed %d", error);
                goto fail;
        }
 
        error = dlm_process_requestqueue(ls);
        if (error) {
-               log_error(ls, "process_requestqueue failed %d", error);
+               log_debug(ls, "process_requestqueue failed %d", error);
                goto fail;
        }
 
        error = dlm_recover_waiters_post(ls);
        if (error) {
-               log_error(ls, "recover_waiters_post failed %d", error);
+               log_debug(ls, "recover_waiters_post failed %d", error);
                goto fail;
        }
 
index c37e93e..d378b7f 100644 (file)
@@ -180,6 +180,14 @@ void dlm_user_add_ast(struct dlm_lkb *lkb, int type)
            ua->lksb.sb_status == -EAGAIN && !list_empty(&lkb->lkb_ownqueue))
                remove_ownqueue = 1;
 
+       /* unlocks or cancels of waiting requests need to be removed from the
+          proc's unlocking list, again there must be a better way...  */
+
+       if (ua->lksb.sb_status == -DLM_EUNLOCK ||
+           (ua->lksb.sb_status == -DLM_ECANCEL &&
+            lkb->lkb_grmode == DLM_LOCK_IV))
+               remove_ownqueue = 1;
+
        /* We want to copy the lvb to userspace when the completion
           ast is read if the status is 0, the lock has an lvb and
           lvb_ops says we should.  We could probably have set_lvb_lock()
@@ -523,6 +531,7 @@ static int device_open(struct inode *inode, struct file *file)
        proc->lockspace = ls->ls_local_handle;
        INIT_LIST_HEAD(&proc->asts);
        INIT_LIST_HEAD(&proc->locks);
+       INIT_LIST_HEAD(&proc->unlocking);
        spin_lock_init(&proc->asts_spin);
        spin_lock_init(&proc->locks_spin);
        init_waitqueue_head(&proc->wait);
index 767197d..963889c 100644 (file)
@@ -134,6 +134,8 @@ void dlm_rcom_out(struct dlm_rcom *rc)
        rc->rc_type             = cpu_to_le32(rc->rc_type);
        rc->rc_result           = cpu_to_le32(rc->rc_result);
        rc->rc_id               = cpu_to_le64(rc->rc_id);
+       rc->rc_seq              = cpu_to_le64(rc->rc_seq);
+       rc->rc_seq_reply        = cpu_to_le64(rc->rc_seq_reply);
 
        if (type == DLM_RCOM_LOCK)
                rcom_lock_out((struct rcom_lock *) rc->rc_buf);
@@ -151,6 +153,8 @@ void dlm_rcom_in(struct dlm_rcom *rc)
        rc->rc_type             = le32_to_cpu(rc->rc_type);
        rc->rc_result           = le32_to_cpu(rc->rc_result);
        rc->rc_id               = le64_to_cpu(rc->rc_id);
+       rc->rc_seq              = le64_to_cpu(rc->rc_seq);
+       rc->rc_seq_reply        = le64_to_cpu(rc->rc_seq_reply);
 
        if (rc->rc_type == DLM_RCOM_LOCK)
                rcom_lock_in((struct rcom_lock *) rc->rc_buf);
index 6a2ffa2..de8e64c 100644 (file)
@@ -4,44 +4,43 @@ config GFS2_FS
        select FS_POSIX_ACL
        select CRC32
        help
-       A cluster filesystem.
+         A cluster filesystem.
 
-       Allows a cluster of computers to simultaneously use a block device
-       that is shared between them (with FC, iSCSI, NBD, etc...).  GFS reads
-       and writes to the block device like a local filesystem, but also uses
-       a lock module to allow the computers coordinate their I/O so
-       filesystem consistency is maintained.  One of the nifty features of
-       GFS is perfect consistency -- changes made to the filesystem on one
-       machine show up immediately on all other machines in the cluster.
+         Allows a cluster of computers to simultaneously use a block device
+         that is shared between them (with FC, iSCSI, NBD, etc...).  GFS reads
+         and writes to the block device like a local filesystem, but also uses
+         a lock module to allow the computers coordinate their I/O so
+         filesystem consistency is maintained.  One of the nifty features of
+         GFS is perfect consistency -- changes made to the filesystem on one
+         machine show up immediately on all other machines in the cluster.
 
-       To use the GFS2 filesystem, you will need to enable one or more of
-       the below locking modules. Documentation and utilities for GFS2 can
-       be found here: http://sources.redhat.com/cluster
+         To use the GFS2 filesystem, you will need to enable one or more of
+         the below locking modules. Documentation and utilities for GFS2 can
+         be found here: http://sources.redhat.com/cluster
 
 config GFS2_FS_LOCKING_NOLOCK
        tristate "GFS2 \"nolock\" locking module"
        depends on GFS2_FS
        help
-       Single node locking module for GFS2.
+         Single node locking module for GFS2.
 
-       Use this module if you want to use GFS2 on a single node without
-       its clustering features. You can still take advantage of the
-       large file support, and upgrade to running a full cluster later on
-       if required.
+         Use this module if you want to use GFS2 on a single node without
+         its clustering features. You can still take advantage of the
+         large file support, and upgrade to running a full cluster later on
+         if required.
 
-       If you will only be using GFS2 in cluster mode, you do not need this
-       module.
+         If you will only be using GFS2 in cluster mode, you do not need this
+         module.
 
 config GFS2_FS_LOCKING_DLM
        tristate "GFS2 DLM locking module"
-       depends on GFS2_FS && NET && INET && (IPV6 || IPV6=n)
+       depends on GFS2_FS && SYSFS && NET && INET && (IPV6 || IPV6=n)
        select IP_SCTP if DLM_SCTP
        select CONFIGFS_FS
        select DLM
        help
-       Multiple node locking module for GFS2
-
-       Most users of GFS2 will require this module. It provides the locking
-       interface between GFS2 and the DLM, which is required to use GFS2
-       in a cluster environment.
+         Multiple node locking module for GFS2
 
+         Most users of GFS2 will require this module. It provides the locking
+         interface between GFS2 and the DLM, which is required to use GFS2
+         in a cluster environment.
index 8240c1f..113f6c9 100644 (file)
@@ -773,7 +773,7 @@ static int do_strip(struct gfs2_inode *ip, struct buffer_head *dibh,
                        gfs2_free_data(ip, bstart, blen);
        }
 
-       ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+       ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 
        gfs2_dinode_out(ip, dibh->b_data);
 
@@ -848,7 +848,7 @@ static int do_grow(struct gfs2_inode *ip, u64 size)
        }
 
        ip->i_di.di_size = size;
-       ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+       ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 
        error = gfs2_meta_inode_buffer(ip, &dibh);
        if (error)
@@ -963,7 +963,7 @@ static int trunc_start(struct gfs2_inode *ip, u64 size)
 
        if (gfs2_is_stuffed(ip)) {
                ip->i_di.di_size = size;
-               ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+               ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
                gfs2_trans_add_bh(ip->i_gl, dibh, 1);
                gfs2_dinode_out(ip, dibh->b_data);
                gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode) + size);
@@ -975,7 +975,7 @@ static int trunc_start(struct gfs2_inode *ip, u64 size)
 
                if (!error) {
                        ip->i_di.di_size = size;
-                       ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+                       ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
                        ip->i_di.di_flags |= GFS2_DIF_TRUNC_IN_PROG;
                        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
                        gfs2_dinode_out(ip, dibh->b_data);
@@ -1048,7 +1048,7 @@ static int trunc_end(struct gfs2_inode *ip)
                        ip->i_num.no_addr;
                gfs2_buffer_clear_tail(dibh, sizeof(struct gfs2_dinode));
        }
-       ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+       ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
        ip->i_di.di_flags &= ~GFS2_DIF_TRUNC_IN_PROG;
 
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
index 0fdcb77..c93ca8f 100644 (file)
@@ -131,7 +131,7 @@ static int gfs2_dir_write_stuffed(struct gfs2_inode *ip, const char *buf,
        memcpy(dibh->b_data + offset + sizeof(struct gfs2_dinode), buf, size);
        if (ip->i_di.di_size < offset + size)
                ip->i_di.di_size = offset + size;
-       ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+       ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
        gfs2_dinode_out(ip, dibh->b_data);
 
        brelse(dibh);
@@ -229,7 +229,7 @@ out:
 
        if (ip->i_di.di_size < offset + copied)
                ip->i_di.di_size = offset + copied;
-       ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+       ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
        gfs2_dinode_out(ip, dibh->b_data);
@@ -1198,12 +1198,11 @@ static int compare_dents(const void *a, const void *b)
  */
 
 static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
-                          void *opaque, gfs2_filldir_t filldir,
+                          void *opaque, filldir_t filldir,
                           const struct gfs2_dirent **darr, u32 entries,
                           int *copied)
 {
        const struct gfs2_dirent *dent, *dent_next;
-       struct gfs2_inum_host inum;
        u64 off, off_next;
        unsigned int x, y;
        int run = 0;
@@ -1240,11 +1239,9 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
                        *offset = off;
                }
 
-               gfs2_inum_in(&inum, (char *)&dent->de_inum);
-
                error = filldir(opaque, (const char *)(dent + 1),
                                be16_to_cpu(dent->de_name_len),
-                               off, &inum,
+                               off, be64_to_cpu(dent->de_inum.no_addr),
                                be16_to_cpu(dent->de_type));
                if (error)
                        return 1;
@@ -1262,8 +1259,8 @@ static int do_filldir_main(struct gfs2_inode *dip, u64 *offset,
 }
 
 static int gfs2_dir_read_leaf(struct inode *inode, u64 *offset, void *opaque,
-                             gfs2_filldir_t filldir, int *copied,
-                             unsigned *depth, u64 leaf_no)
+                             filldir_t filldir, int *copied, unsigned *depth,
+                             u64 leaf_no)
 {
        struct gfs2_inode *ip = GFS2_I(inode);
        struct buffer_head *bh;
@@ -1343,7 +1340,7 @@ out:
  */
 
 static int dir_e_read(struct inode *inode, u64 *offset, void *opaque,
-                     gfs2_filldir_t filldir)
+                     filldir_t filldir)
 {
        struct gfs2_inode *dip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
@@ -1402,7 +1399,7 @@ out:
 }
 
 int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
-                 gfs2_filldir_t filldir)
+                 filldir_t filldir)
 {
        struct gfs2_inode *dip = GFS2_I(inode);
        struct dirent_gather g;
@@ -1568,7 +1565,7 @@ int gfs2_dir_add(struct inode *inode, const struct qstr *name,
                                break;
                        gfs2_trans_add_bh(ip->i_gl, bh, 1);
                        ip->i_di.di_entries++;
-                       ip->i_inode.i_mtime.tv_sec = ip->i_inode.i_ctime.tv_sec = get_seconds();
+                       ip->i_inode.i_mtime = ip->i_inode.i_ctime = CURRENT_TIME_SEC;
                        gfs2_dinode_out(ip, bh->b_data);
                        brelse(bh);
                        error = 0;
@@ -1654,7 +1651,7 @@ int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *name)
                gfs2_consist_inode(dip);
        gfs2_trans_add_bh(dip->i_gl, bh, 1);
        dip->i_di.di_entries--;
-       dip->i_inode.i_mtime.tv_sec = dip->i_inode.i_ctime.tv_sec = get_seconds();
+       dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME_SEC;
        gfs2_dinode_out(dip, bh->b_data);
        brelse(bh);
        mark_inode_dirty(&dip->i_inode);
@@ -1702,7 +1699,7 @@ int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
                gfs2_trans_add_bh(dip->i_gl, bh, 1);
        }
 
-       dip->i_inode.i_mtime.tv_sec = dip->i_inode.i_ctime.tv_sec = get_seconds();
+       dip->i_inode.i_mtime = dip->i_inode.i_ctime = CURRENT_TIME_SEC;
        gfs2_dinode_out(dip, bh->b_data);
        brelse(bh);
        return 0;
index b21b336..48fe890 100644 (file)
@@ -16,30 +16,13 @@ struct inode;
 struct gfs2_inode;
 struct gfs2_inum;
 
-/**
- * gfs2_filldir_t - Report a directory entry to the caller of gfs2_dir_read()
- * @opaque: opaque data used by the function
- * @name: the name of the directory entry
- * @length: the length of the name
- * @offset: the entry's offset in the directory
- * @inum: the inode number the entry points to
- * @type: the type of inode the entry points to
- *
- * Returns: 0 on success, 1 if buffer full
- */
-
-typedef int (*gfs2_filldir_t) (void *opaque,
-                             const char *name, unsigned int length,
-                             u64 offset,
-                             struct gfs2_inum_host *inum, unsigned int type);
-
 int gfs2_dir_search(struct inode *dir, const struct qstr *filename,
                    struct gfs2_inum_host *inum, unsigned int *type);
 int gfs2_dir_add(struct inode *inode, const struct qstr *filename,
                 const struct gfs2_inum_host *inum, unsigned int type);
 int gfs2_dir_del(struct gfs2_inode *dip, const struct qstr *filename);
-int gfs2_dir_read(struct inode *inode, u64 * offset, void *opaque,
-                 gfs2_filldir_t filldir);
+int gfs2_dir_read(struct inode *inode, u64 *offset, void *opaque,
+                 filldir_t filldir);
 int gfs2_dir_mvino(struct gfs2_inode *dip, const struct qstr *filename,
                   struct gfs2_inum_host *new_inum, unsigned int new_type);
 
index ebebbdc..0c83c7f 100644 (file)
@@ -301,7 +301,7 @@ static int ea_dealloc_unstuffed(struct gfs2_inode *ip, struct buffer_head *bh,
 
        error = gfs2_meta_inode_buffer(ip, &dibh);
        if (!error) {
-               ip->i_inode.i_ctime.tv_sec = get_seconds();
+               ip->i_inode.i_ctime = CURRENT_TIME_SEC;
                gfs2_trans_add_bh(ip->i_gl, dibh, 1);
                gfs2_dinode_out(ip, dibh->b_data);
                brelse(dibh);
@@ -718,7 +718,7 @@ static int ea_alloc_skeleton(struct gfs2_inode *ip, struct gfs2_ea_request *er,
                                            (er->er_mode & S_IFMT));
                        ip->i_inode.i_mode = er->er_mode;
                }
-               ip->i_inode.i_ctime.tv_sec = get_seconds();
+               ip->i_inode.i_ctime = CURRENT_TIME_SEC;
                gfs2_trans_add_bh(ip->i_gl, dibh, 1);
                gfs2_dinode_out(ip, dibh->b_data);
                brelse(dibh);
@@ -853,7 +853,7 @@ static int ea_set_simple_noalloc(struct gfs2_inode *ip, struct buffer_head *bh,
                        (ip->i_inode.i_mode & S_IFMT) == (er->er_mode & S_IFMT));
                ip->i_inode.i_mode = er->er_mode;
        }
-       ip->i_inode.i_ctime.tv_sec = get_seconds();
+       ip->i_inode.i_ctime = CURRENT_TIME_SEC;
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
        gfs2_dinode_out(ip, dibh->b_data);
        brelse(dibh);
@@ -1134,7 +1134,7 @@ static int ea_remove_stuffed(struct gfs2_inode *ip, struct gfs2_ea_location *el)
 
        error = gfs2_meta_inode_buffer(ip, &dibh);
        if (!error) {
-               ip->i_inode.i_ctime.tv_sec = get_seconds();
+               ip->i_inode.i_ctime = CURRENT_TIME_SEC;
                gfs2_trans_add_bh(ip->i_gl, dibh, 1);
                gfs2_dinode_out(ip, dibh->b_data);
                brelse(dibh);
index 4381469..6618c11 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/gfs2_ondisk.h>
 #include <linux/list.h>
 #include <linux/lm_interface.h>
+#include <linux/wait.h>
+#include <linux/rwsem.h>
 #include <asm/uaccess.h>
 
 #include "gfs2.h"
 #include "super.h"
 #include "util.h"
 
-struct greedy {
-       struct gfs2_holder gr_gh;
-       struct delayed_work gr_work;
-};
-
 struct gfs2_gl_hash_bucket {
         struct hlist_head hb_list;
 };
@@ -47,6 +44,9 @@ typedef void (*glock_examiner) (struct gfs2_glock * gl);
 static int gfs2_dump_lockstate(struct gfs2_sbd *sdp);
 static int dump_glock(struct gfs2_glock *gl);
 static int dump_inode(struct gfs2_inode *ip);
+static void gfs2_glock_xmote_th(struct gfs2_holder *gh);
+static void gfs2_glock_drop_th(struct gfs2_glock *gl);
+static DECLARE_RWSEM(gfs2_umount_flush_sem);
 
 #define GFS2_GL_HASH_SHIFT      15
 #define GFS2_GL_HASH_SIZE       (1 << GFS2_GL_HASH_SHIFT)
@@ -212,30 +212,6 @@ out:
        return rv;
 }
 
-/**
- * queue_empty - check to see if a glock's queue is empty
- * @gl: the glock
- * @head: the head of the queue to check
- *
- * This function protects the list in the event that a process already
- * has a holder on the list and is adding a second holder for itself.
- * The glmutex lock is what generally prevents processes from working
- * on the same glock at once, but the special case of adding a second
- * holder for yourself ("recursive" locking) doesn't involve locking
- * glmutex, making the spin lock necessary.
- *
- * Returns: 1 if the queue is empty
- */
-
-static inline int queue_empty(struct gfs2_glock *gl, struct list_head *head)
-{
-       int empty;
-       spin_lock(&gl->gl_spin);
-       empty = list_empty(head);
-       spin_unlock(&gl->gl_spin);
-       return empty;
-}
-
 /**
  * search_bucket() - Find struct gfs2_glock by lock number
  * @bucket: the bucket to search
@@ -395,11 +371,6 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
        gh->gh_flags = flags;
        gh->gh_error = 0;
        gh->gh_iflags = 0;
-       init_completion(&gh->gh_wait);
-
-       if (gh->gh_state == LM_ST_EXCLUSIVE)
-               gh->gh_flags |= GL_LOCAL_EXCL;
-
        gfs2_glock_hold(gl);
 }
 
@@ -417,9 +388,6 @@ void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *
 {
        gh->gh_state = state;
        gh->gh_flags = flags;
-       if (gh->gh_state == LM_ST_EXCLUSIVE)
-               gh->gh_flags |= GL_LOCAL_EXCL;
-
        gh->gh_iflags &= 1 << HIF_ALLOCED;
        gh->gh_ip = (unsigned long)__builtin_return_address(0);
 }
@@ -479,6 +447,29 @@ static void gfs2_holder_put(struct gfs2_holder *gh)
        kfree(gh);
 }
 
+static void gfs2_holder_dispose_or_wake(struct gfs2_holder *gh)
+{
+       if (test_bit(HIF_DEALLOC, &gh->gh_iflags)) {
+               gfs2_holder_put(gh);
+               return;
+       }
+       clear_bit(HIF_WAIT, &gh->gh_iflags);
+       smp_mb();
+       wake_up_bit(&gh->gh_iflags, HIF_WAIT);
+}
+
+static int holder_wait(void *word)
+{
+        schedule();
+        return 0;
+}
+
+static void wait_on_holder(struct gfs2_holder *gh)
+{
+       might_sleep();
+       wait_on_bit(&gh->gh_iflags, HIF_WAIT, holder_wait, TASK_UNINTERRUPTIBLE);
+}
+
 /**
  * rq_mutex - process a mutex request in the queue
  * @gh: the glock holder
@@ -493,7 +484,9 @@ static int rq_mutex(struct gfs2_holder *gh)
        list_del_init(&gh->gh_list);
        /*  gh->gh_error never examined.  */
        set_bit(GLF_LOCK, &gl->gl_flags);
-       complete(&gh->gh_wait);
+       clear_bit(HIF_WAIT, &gh->gh_iflags);
+       smp_mb();
+       wake_up_bit(&gh->gh_iflags, HIF_WAIT);
 
        return 1;
 }
@@ -511,7 +504,6 @@ static int rq_promote(struct gfs2_holder *gh)
 {
        struct gfs2_glock *gl = gh->gh_gl;
        struct gfs2_sbd *sdp = gl->gl_sbd;
-       const struct gfs2_glock_operations *glops = gl->gl_ops;
 
        if (!relaxed_state_ok(gl->gl_state, gh->gh_state, gh->gh_flags)) {
                if (list_empty(&gl->gl_holders)) {
@@ -526,7 +518,7 @@ static int rq_promote(struct gfs2_holder *gh)
                                gfs2_reclaim_glock(sdp);
                        }
 
-                       glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags);
+                       gfs2_glock_xmote_th(gh);
                        spin_lock(&gl->gl_spin);
                }
                return 1;
@@ -537,11 +529,11 @@ static int rq_promote(struct gfs2_holder *gh)
                set_bit(GLF_LOCK, &gl->gl_flags);
        } else {
                struct gfs2_holder *next_gh;
-               if (gh->gh_flags & GL_LOCAL_EXCL)
+               if (gh->gh_state == LM_ST_EXCLUSIVE)
                        return 1;
                next_gh = list_entry(gl->gl_holders.next, struct gfs2_holder,
                                     gh_list);
-               if (next_gh->gh_flags & GL_LOCAL_EXCL)
+               if (next_gh->gh_state == LM_ST_EXCLUSIVE)
                         return 1;
        }
 
@@ -549,7 +541,7 @@ static int rq_promote(struct gfs2_holder *gh)
        gh->gh_error = 0;
        set_bit(HIF_HOLDER, &gh->gh_iflags);
 
-       complete(&gh->gh_wait);
+       gfs2_holder_dispose_or_wake(gh);
 
        return 0;
 }
@@ -564,7 +556,6 @@ static int rq_promote(struct gfs2_holder *gh)
 static int rq_demote(struct gfs2_holder *gh)
 {
        struct gfs2_glock *gl = gh->gh_gl;
-       const struct gfs2_glock_operations *glops = gl->gl_ops;
 
        if (!list_empty(&gl->gl_holders))
                return 1;
@@ -573,10 +564,7 @@ static int rq_demote(struct gfs2_holder *gh)
                list_del_init(&gh->gh_list);
                gh->gh_error = 0;
                spin_unlock(&gl->gl_spin);
-               if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
-                       gfs2_holder_put(gh);
-               else
-                       complete(&gh->gh_wait);
+               gfs2_holder_dispose_or_wake(gh);
                spin_lock(&gl->gl_spin);
        } else {
                gl->gl_req_gh = gh;
@@ -585,9 +573,9 @@ static int rq_demote(struct gfs2_holder *gh)
 
                if (gh->gh_state == LM_ST_UNLOCKED ||
                    gl->gl_state != LM_ST_EXCLUSIVE)
-                       glops->go_drop_th(gl);
+                       gfs2_glock_drop_th(gl);
                else
-                       glops->go_xmote_th(gl, gh->gh_state, gh->gh_flags);
+                       gfs2_glock_xmote_th(gh);
 
                spin_lock(&gl->gl_spin);
        }
@@ -595,30 +583,6 @@ static int rq_demote(struct gfs2_holder *gh)
        return 0;
 }
 
-/**
- * rq_greedy - process a queued request to drop greedy status
- * @gh: the glock holder
- *
- * Returns: 1 if the queue is blocked
- */
-
-static int rq_greedy(struct gfs2_holder *gh)
-{
-       struct gfs2_glock *gl = gh->gh_gl;
-
-       list_del_init(&gh->gh_list);
-       /*  gh->gh_error never examined.  */
-       clear_bit(GLF_GREEDY, &gl->gl_flags);
-       spin_unlock(&gl->gl_spin);
-
-       gfs2_holder_uninit(gh);
-       kfree(container_of(gh, struct greedy, gr_gh));
-
-       spin_lock(&gl->gl_spin);
-
-       return 0;
-}
-
 /**
  * run_queue - process holder structures on a glock
  * @gl: the glock
@@ -649,8 +613,6 @@ static void run_queue(struct gfs2_glock *gl)
 
                        if (test_bit(HIF_DEMOTE, &gh->gh_iflags))
                                blocked = rq_demote(gh);
-                       else if (test_bit(HIF_GREEDY, &gh->gh_iflags))
-                               blocked = rq_greedy(gh);
                        else
                                gfs2_assert_warn(gl->gl_sbd, 0);
 
@@ -684,6 +646,8 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl)
 
        gfs2_holder_init(gl, 0, 0, &gh);
        set_bit(HIF_MUTEX, &gh.gh_iflags);
+       if (test_and_set_bit(HIF_WAIT, &gh.gh_iflags))
+               BUG();
 
        spin_lock(&gl->gl_spin);
        if (test_and_set_bit(GLF_LOCK, &gl->gl_flags)) {
@@ -691,11 +655,13 @@ static void gfs2_glmutex_lock(struct gfs2_glock *gl)
        } else {
                gl->gl_owner = current;
                gl->gl_ip = (unsigned long)__builtin_return_address(0);
-               complete(&gh.gh_wait);
+               clear_bit(HIF_WAIT, &gh.gh_iflags);
+               smp_mb();
+               wake_up_bit(&gh.gh_iflags, HIF_WAIT);
        }
        spin_unlock(&gl->gl_spin);
 
-       wait_for_completion(&gh.gh_wait);
+       wait_on_holder(&gh);
        gfs2_holder_uninit(&gh);
 }
 
@@ -774,6 +740,7 @@ restart:
                        return;
                set_bit(HIF_DEMOTE, &new_gh->gh_iflags);
                set_bit(HIF_DEALLOC, &new_gh->gh_iflags);
+               set_bit(HIF_WAIT, &new_gh->gh_iflags);
 
                goto restart;
        }
@@ -825,7 +792,7 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
        int op_done = 1;
 
        gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
-       gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+       gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
        gfs2_assert_warn(sdp, !(ret & LM_OUT_ASYNC));
 
        state_change(gl, ret & LM_OUT_ST_MASK);
@@ -908,12 +875,8 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
 
        gfs2_glock_put(gl);
 
-       if (gh) {
-               if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
-                       gfs2_holder_put(gh);
-               else
-                       complete(&gh->gh_wait);
-       }
+       if (gh)
+               gfs2_holder_dispose_or_wake(gh);
 }
 
 /**
@@ -924,23 +887,26 @@ static void xmote_bh(struct gfs2_glock *gl, unsigned int ret)
  *
  */
 
-void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags)
+void gfs2_glock_xmote_th(struct gfs2_holder *gh)
 {
+       struct gfs2_glock *gl = gh->gh_gl;
        struct gfs2_sbd *sdp = gl->gl_sbd;
+       int flags = gh->gh_flags;
+       unsigned state = gh->gh_state;
        const struct gfs2_glock_operations *glops = gl->gl_ops;
        int lck_flags = flags & (LM_FLAG_TRY | LM_FLAG_TRY_1CB |
                                 LM_FLAG_NOEXP | LM_FLAG_ANY |
                                 LM_FLAG_PRIORITY);
        unsigned int lck_ret;
 
+       if (glops->go_xmote_th)
+               glops->go_xmote_th(gl);
+
        gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
-       gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+       gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
        gfs2_assert_warn(sdp, state != LM_ST_UNLOCKED);
        gfs2_assert_warn(sdp, state != gl->gl_state);
 
-       if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync)
-               glops->go_sync(gl);
-
        gfs2_glock_hold(gl);
        gl->gl_req_bh = xmote_bh;
 
@@ -971,10 +937,8 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
        const struct gfs2_glock_operations *glops = gl->gl_ops;
        struct gfs2_holder *gh = gl->gl_req_gh;
 
-       clear_bit(GLF_PREFETCH, &gl->gl_flags);
-
        gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
-       gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+       gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
        gfs2_assert_warn(sdp, !ret);
 
        state_change(gl, LM_ST_UNLOCKED);
@@ -1001,12 +965,8 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
 
        gfs2_glock_put(gl);
 
-       if (gh) {
-               if (test_bit(HIF_DEALLOC, &gh->gh_iflags))
-                       gfs2_holder_put(gh);
-               else
-                       complete(&gh->gh_wait);
-       }
+       if (gh)
+               gfs2_holder_dispose_or_wake(gh);
 }
 
 /**
@@ -1015,19 +975,19 @@ static void drop_bh(struct gfs2_glock *gl, unsigned int ret)
  *
  */
 
-void gfs2_glock_drop_th(struct gfs2_glock *gl)
+static void gfs2_glock_drop_th(struct gfs2_glock *gl)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
        const struct gfs2_glock_operations *glops = gl->gl_ops;
        unsigned int ret;
 
+       if (glops->go_drop_th)
+               glops->go_drop_th(gl);
+
        gfs2_assert_warn(sdp, test_bit(GLF_LOCK, &gl->gl_flags));
-       gfs2_assert_warn(sdp, queue_empty(gl, &gl->gl_holders));
+       gfs2_assert_warn(sdp, list_empty(&gl->gl_holders));
        gfs2_assert_warn(sdp, gl->gl_state != LM_ST_UNLOCKED);
 
-       if (gl->gl_state == LM_ST_EXCLUSIVE && glops->go_sync)
-               glops->go_sync(gl);
-
        gfs2_glock_hold(gl);
        gl->gl_req_bh = drop_bh;
 
@@ -1107,8 +1067,7 @@ static int glock_wait_internal(struct gfs2_holder *gh)
        if (gh->gh_flags & LM_FLAG_PRIORITY)
                do_cancels(gh);
 
-       wait_for_completion(&gh->gh_wait);
-
+       wait_on_holder(gh);
        if (gh->gh_error)
                return gh->gh_error;
 
@@ -1164,6 +1123,8 @@ static void add_to_queue(struct gfs2_holder *gh)
        struct gfs2_holder *existing;
 
        BUG_ON(!gh->gh_owner);
+       if (test_and_set_bit(HIF_WAIT, &gh->gh_iflags))
+               BUG();
 
        existing = find_holder_by_owner(&gl->gl_holders, gh->gh_owner);
        if (existing) {
@@ -1227,8 +1188,6 @@ restart:
                }
        }
 
-       clear_bit(GLF_PREFETCH, &gl->gl_flags);
-
        return error;
 }
 
@@ -1320,98 +1279,6 @@ void gfs2_glock_dq(struct gfs2_holder *gh)
        spin_unlock(&gl->gl_spin);
 }
 
-/**
- * gfs2_glock_prefetch - Try to prefetch a glock
- * @gl: the glock
- * @state: the state to prefetch in
- * @flags: flags passed to go_xmote_th()
- *
- */
-
-static void gfs2_glock_prefetch(struct gfs2_glock *gl, unsigned int state,
-                               int flags)
-{
-       const struct gfs2_glock_operations *glops = gl->gl_ops;
-
-       spin_lock(&gl->gl_spin);
-
-       if (test_bit(GLF_LOCK, &gl->gl_flags) || !list_empty(&gl->gl_holders) ||
-           !list_empty(&gl->gl_waiters1) || !list_empty(&gl->gl_waiters2) ||
-           !list_empty(&gl->gl_waiters3) ||
-           relaxed_state_ok(gl->gl_state, state, flags)) {
-               spin_unlock(&gl->gl_spin);
-               return;
-       }
-
-       set_bit(GLF_PREFETCH, &gl->gl_flags);
-       set_bit(GLF_LOCK, &gl->gl_flags);
-       spin_unlock(&gl->gl_spin);
-
-       glops->go_xmote_th(gl, state, flags);
-}
-
-static void greedy_work(struct work_struct *work)
-{
-       struct greedy *gr = container_of(work, struct greedy, gr_work.work);
-       struct gfs2_holder *gh = &gr->gr_gh;
-       struct gfs2_glock *gl = gh->gh_gl;
-       const struct gfs2_glock_operations *glops = gl->gl_ops;
-
-       clear_bit(GLF_SKIP_WAITERS2, &gl->gl_flags);
-
-       if (glops->go_greedy)
-               glops->go_greedy(gl);
-
-       spin_lock(&gl->gl_spin);
-
-       if (list_empty(&gl->gl_waiters2)) {
-               clear_bit(GLF_GREEDY, &gl->gl_flags);
-               spin_unlock(&gl->gl_spin);
-               gfs2_holder_uninit(gh);
-               kfree(gr);
-       } else {
-               gfs2_glock_hold(gl);
-               list_add_tail(&gh->gh_list, &gl->gl_waiters2);
-               run_queue(gl);
-               spin_unlock(&gl->gl_spin);
-               gfs2_glock_put(gl);
-       }
-}
-
-/**
- * gfs2_glock_be_greedy -
- * @gl:
- * @time:
- *
- * Returns: 0 if go_greedy will be called, 1 otherwise
- */
-
-int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time)
-{
-       struct greedy *gr;
-       struct gfs2_holder *gh;
-
-       if (!time || gl->gl_sbd->sd_args.ar_localcaching ||
-           test_and_set_bit(GLF_GREEDY, &gl->gl_flags))
-               return 1;
-
-       gr = kmalloc(sizeof(struct greedy), GFP_KERNEL);
-       if (!gr) {
-               clear_bit(GLF_GREEDY, &gl->gl_flags);
-               return 1;
-       }
-       gh = &gr->gr_gh;
-
-       gfs2_holder_init(gl, 0, 0, gh);
-       set_bit(HIF_GREEDY, &gh->gh_iflags);
-       INIT_DELAYED_WORK(&gr->gr_work, greedy_work);
-
-       set_bit(GLF_SKIP_WAITERS2, &gl->gl_flags);
-       schedule_delayed_work(&gr->gr_work, time);
-
-       return 0;
-}
-
 /**
  * gfs2_glock_dq_uninit - dequeue a holder from a glock and initialize it
  * @gh: the holder structure
@@ -1470,10 +1337,7 @@ static int glock_compare(const void *arg_a, const void *arg_b)
                return 1;
        if (a->ln_number < b->ln_number)
                return -1;
-       if (gh_a->gh_state == LM_ST_SHARED && gh_b->gh_state == LM_ST_EXCLUSIVE)
-               return 1;
-       if (!(gh_a->gh_flags & GL_LOCAL_EXCL) && (gh_b->gh_flags & GL_LOCAL_EXCL))
-               return 1;
+       BUG_ON(gh_a->gh_gl->gl_ops->go_type == gh_b->gh_gl->gl_ops->go_type);
        return 0;
 }
 
@@ -1617,34 +1481,6 @@ void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs)
                gfs2_glock_dq_uninit(&ghs[x]);
 }
 
-/**
- * gfs2_glock_prefetch_num - prefetch a glock based on lock number
- * @sdp: the filesystem
- * @number: the lock number
- * @glops: the glock operations for the type of glock
- * @state: the state to acquire the glock in
- * @flags: modifier flags for the aquisition
- *
- * Returns: errno
- */
-
-void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number,
-                            const struct gfs2_glock_operations *glops,
-                            unsigned int state, int flags)
-{
-       struct gfs2_glock *gl;
-       int error;
-
-       if (atomic_read(&sdp->sd_reclaim_count) <
-           gfs2_tune_get(sdp, gt_reclaim_limit)) {
-               error = gfs2_glock_get(sdp, number, glops, CREATE, &gl);
-               if (!error) {
-                       gfs2_glock_prefetch(gl, state, flags);
-                       gfs2_glock_put(gl);
-               }
-       }
-}
-
 /**
  * gfs2_lvb_hold - attach a LVB from a glock
  * @gl: The glock in question
@@ -1703,8 +1539,6 @@ static void blocking_cb(struct gfs2_sbd *sdp, struct lm_lockname *name,
        if (!gl)
                return;
 
-       if (gl->gl_ops->go_callback)
-               gl->gl_ops->go_callback(gl, state);
        handle_callback(gl, state);
 
        spin_lock(&gl->gl_spin);
@@ -1746,12 +1580,14 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data)
                struct lm_async_cb *async = data;
                struct gfs2_glock *gl;
 
+               down_read(&gfs2_umount_flush_sem);
                gl = gfs2_glock_find(sdp, &async->lc_name);
                if (gfs2_assert_warn(sdp, gl))
                        return;
                if (!gfs2_assert_warn(sdp, gl->gl_req_bh))
                        gl->gl_req_bh(gl, async->lc_ret);
                gfs2_glock_put(gl);
+               up_read(&gfs2_umount_flush_sem);
                return;
        }
 
@@ -1781,15 +1617,11 @@ void gfs2_glock_cb(void *cb_data, unsigned int type, void *data)
 
 static int demote_ok(struct gfs2_glock *gl)
 {
-       struct gfs2_sbd *sdp = gl->gl_sbd;
        const struct gfs2_glock_operations *glops = gl->gl_ops;
        int demote = 1;
 
        if (test_bit(GLF_STICKY, &gl->gl_flags))
                demote = 0;
-       else if (test_bit(GLF_PREFETCH, &gl->gl_flags))
-               demote = time_after_eq(jiffies, gl->gl_stamp +
-                                   gfs2_tune_get(sdp, gt_prefetch_secs) * HZ);
        else if (glops->go_demote_ok)
                demote = glops->go_demote_ok(gl);
 
@@ -1845,7 +1677,7 @@ void gfs2_reclaim_glock(struct gfs2_sbd *sdp)
        atomic_inc(&sdp->sd_reclaimed);
 
        if (gfs2_glmutex_trylock(gl)) {
-               if (queue_empty(gl, &gl->gl_holders) &&
+               if (list_empty(&gl->gl_holders) &&
                    gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
                        handle_callback(gl, LM_ST_UNLOCKED);
                gfs2_glmutex_unlock(gl);
@@ -1909,7 +1741,7 @@ static void scan_glock(struct gfs2_glock *gl)
                return;
 
        if (gfs2_glmutex_trylock(gl)) {
-               if (queue_empty(gl, &gl->gl_holders) &&
+               if (list_empty(&gl->gl_holders) &&
                    gl->gl_state != LM_ST_UNLOCKED && demote_ok(gl))
                        goto out_schedule;
                gfs2_glmutex_unlock(gl);
@@ -1958,7 +1790,7 @@ static void clear_glock(struct gfs2_glock *gl)
        }
 
        if (gfs2_glmutex_trylock(gl)) {
-               if (queue_empty(gl, &gl->gl_holders) &&
+               if (list_empty(&gl->gl_holders) &&
                    gl->gl_state != LM_ST_UNLOCKED)
                        handle_callback(gl, LM_ST_UNLOCKED);
                gfs2_glmutex_unlock(gl);
@@ -2000,7 +1832,9 @@ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp, int wait)
                        t = jiffies;
                }
 
+               down_write(&gfs2_umount_flush_sem);
                invalidate_inodes(sdp->sd_vfs);
+               up_write(&gfs2_umount_flush_sem);
                msleep(10);
        }
 }
index fb39108..f50e40c 100644 (file)
@@ -20,7 +20,6 @@
 #define LM_FLAG_ANY            0x00000008
 #define LM_FLAG_PRIORITY       0x00000010 */
 
-#define GL_LOCAL_EXCL          0x00000020
 #define GL_ASYNC               0x00000040
 #define GL_EXACT               0x00000080
 #define GL_SKIP                        0x00000100
@@ -83,17 +82,11 @@ void gfs2_holder_init(struct gfs2_glock *gl, unsigned int state, unsigned flags,
 void gfs2_holder_reinit(unsigned int state, unsigned flags,
                        struct gfs2_holder *gh);
 void gfs2_holder_uninit(struct gfs2_holder *gh);
-
-void gfs2_glock_xmote_th(struct gfs2_glock *gl, unsigned int state, int flags);
-void gfs2_glock_drop_th(struct gfs2_glock *gl);
-
 int gfs2_glock_nq(struct gfs2_holder *gh);
 int gfs2_glock_poll(struct gfs2_holder *gh);
 int gfs2_glock_wait(struct gfs2_holder *gh);
 void gfs2_glock_dq(struct gfs2_holder *gh);
 
-int gfs2_glock_be_greedy(struct gfs2_glock *gl, unsigned int time);
-
 void gfs2_glock_dq_uninit(struct gfs2_holder *gh);
 int gfs2_glock_nq_num(struct gfs2_sbd *sdp,
                      u64 number, const struct gfs2_glock_operations *glops,
@@ -103,10 +96,6 @@ int gfs2_glock_nq_m(unsigned int num_gh, struct gfs2_holder *ghs);
 void gfs2_glock_dq_m(unsigned int num_gh, struct gfs2_holder *ghs);
 void gfs2_glock_dq_uninit_m(unsigned int num_gh, struct gfs2_holder *ghs);
 
-void gfs2_glock_prefetch_num(struct gfs2_sbd *sdp, u64 number,
-                            const struct gfs2_glock_operations *glops,
-                            unsigned int state, int flags);
-
 /**
  * gfs2_glock_nq_init - intialize a holder and enqueue it on a glock
  * @gl: the glock
index b068d10..c4b0391 100644 (file)
@@ -117,12 +117,14 @@ static void gfs2_pte_inval(struct gfs2_glock *gl)
 
 static void meta_go_sync(struct gfs2_glock *gl)
 {
+       if (gl->gl_state != LM_ST_EXCLUSIVE)
+               return;
+
        if (test_and_clear_bit(GLF_DIRTY, &gl->gl_flags)) {
                gfs2_log_flush(gl->gl_sbd, gl);
                gfs2_meta_sync(gl);
                gfs2_ail_empty_gl(gl);
        }
-
 }
 
 /**
@@ -141,6 +143,37 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags)
        gl->gl_vn++;
 }
 
+/**
+ * inode_go_sync - Sync the dirty data and/or metadata for an inode glock
+ * @gl: the glock protecting the inode
+ *
+ */
+
+static void inode_go_sync(struct gfs2_glock *gl)
+{
+       struct gfs2_inode *ip = gl->gl_object;
+
+       if (ip && !S_ISREG(ip->i_inode.i_mode))
+               ip = NULL;
+
+       if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
+               gfs2_log_flush(gl->gl_sbd, gl);
+               if (ip)
+                       filemap_fdatawrite(ip->i_inode.i_mapping);
+               gfs2_meta_sync(gl);
+               if (ip) {
+                       struct address_space *mapping = ip->i_inode.i_mapping;
+                       int error = filemap_fdatawait(mapping);
+                       if (error == -ENOSPC)
+                               set_bit(AS_ENOSPC, &mapping->flags);
+                       else if (error)
+                               set_bit(AS_EIO, &mapping->flags);
+               }
+               clear_bit(GLF_DIRTY, &gl->gl_flags);
+               gfs2_ail_empty_gl(gl);
+       }
+}
+
 /**
  * inode_go_xmote_th - promote/demote a glock
  * @gl: the glock
@@ -149,12 +182,12 @@ static void meta_go_inval(struct gfs2_glock *gl, int flags)
  *
  */
 
-static void inode_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
-                             int flags)
+static void inode_go_xmote_th(struct gfs2_glock *gl)
 {
        if (gl->gl_state != LM_ST_UNLOCKED)
                gfs2_pte_inval(gl);
-       gfs2_glock_xmote_th(gl, state, flags);
+       if (gl->gl_state == LM_ST_EXCLUSIVE)
+               inode_go_sync(gl);
 }
 
 /**
@@ -189,38 +222,8 @@ static void inode_go_xmote_bh(struct gfs2_glock *gl)
 static void inode_go_drop_th(struct gfs2_glock *gl)
 {
        gfs2_pte_inval(gl);
-       gfs2_glock_drop_th(gl);
-}
-
-/**
- * inode_go_sync - Sync the dirty data and/or metadata for an inode glock
- * @gl: the glock protecting the inode
- *
- */
-
-static void inode_go_sync(struct gfs2_glock *gl)
-{
-       struct gfs2_inode *ip = gl->gl_object;
-
-       if (ip && !S_ISREG(ip->i_inode.i_mode))
-               ip = NULL;
-
-       if (test_bit(GLF_DIRTY, &gl->gl_flags)) {
-               gfs2_log_flush(gl->gl_sbd, gl);
-               if (ip)
-                       filemap_fdatawrite(ip->i_inode.i_mapping);
-               gfs2_meta_sync(gl);
-               if (ip) {
-                       struct address_space *mapping = ip->i_inode.i_mapping;
-                       int error = filemap_fdatawait(mapping);
-                       if (error == -ENOSPC)
-                               set_bit(AS_ENOSPC, &mapping->flags);
-                       else if (error)
-                               set_bit(AS_EIO, &mapping->flags);
-               }
-               clear_bit(GLF_DIRTY, &gl->gl_flags);
-               gfs2_ail_empty_gl(gl);
-       }
+       if (gl->gl_state == LM_ST_EXCLUSIVE)
+               inode_go_sync(gl);
 }
 
 /**
@@ -295,7 +298,7 @@ static int inode_go_lock(struct gfs2_holder *gh)
 
        if ((ip->i_di.di_flags & GFS2_DIF_TRUNC_IN_PROG) &&
            (gl->gl_state == LM_ST_EXCLUSIVE) &&
-           (gh->gh_flags & GL_LOCAL_EXCL))
+           (gh->gh_state == LM_ST_EXCLUSIVE))
                error = gfs2_truncatei_resume(ip);
 
        return error;
@@ -318,39 +321,6 @@ static void inode_go_unlock(struct gfs2_holder *gh)
                gfs2_meta_cache_flush(ip);
 }
 
-/**
- * inode_greedy -
- * @gl: the glock
- *
- */
-
-static void inode_greedy(struct gfs2_glock *gl)
-{
-       struct gfs2_sbd *sdp = gl->gl_sbd;
-       struct gfs2_inode *ip = gl->gl_object;
-       unsigned int quantum = gfs2_tune_get(sdp, gt_greedy_quantum);
-       unsigned int max = gfs2_tune_get(sdp, gt_greedy_max);
-       unsigned int new_time;
-
-       spin_lock(&ip->i_spin);
-
-       if (time_after(ip->i_last_pfault + quantum, jiffies)) {
-               new_time = ip->i_greedy + quantum;
-               if (new_time > max)
-                       new_time = max;
-       } else {
-               new_time = ip->i_greedy - quantum;
-               if (!new_time || new_time > max)
-                       new_time = 1;
-       }
-
-       ip->i_greedy = new_time;
-
-       spin_unlock(&ip->i_spin);
-
-       iput(&ip->i_inode);
-}
-
 /**
  * rgrp_go_demote_ok - Check to see if it's ok to unlock a RG's glock
  * @gl: the glock
@@ -398,8 +368,7 @@ static void rgrp_go_unlock(struct gfs2_holder *gh)
  *
  */
 
-static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
-                             int flags)
+static void trans_go_xmote_th(struct gfs2_glock *gl)
 {
        struct gfs2_sbd *sdp = gl->gl_sbd;
 
@@ -408,8 +377,6 @@ static void trans_go_xmote_th(struct gfs2_glock *gl, unsigned int state,
                gfs2_meta_syncfs(sdp);
                gfs2_log_shutdown(sdp);
        }
-
-       gfs2_glock_xmote_th(gl, state, flags);
 }
 
 /**
@@ -461,8 +428,6 @@ static void trans_go_drop_th(struct gfs2_glock *gl)
                gfs2_meta_syncfs(sdp);
                gfs2_log_shutdown(sdp);
        }
-
-       gfs2_glock_drop_th(gl);
 }
 
 /**
@@ -478,8 +443,8 @@ static int quota_go_demote_ok(struct gfs2_glock *gl)
 }
 
 const struct gfs2_glock_operations gfs2_meta_glops = {
-       .go_xmote_th = gfs2_glock_xmote_th,
-       .go_drop_th = gfs2_glock_drop_th,
+       .go_xmote_th = meta_go_sync,
+       .go_drop_th = meta_go_sync,
        .go_type = LM_TYPE_META,
 };
 
@@ -487,19 +452,14 @@ const struct gfs2_glock_operations gfs2_inode_glops = {
        .go_xmote_th = inode_go_xmote_th,
        .go_xmote_bh = inode_go_xmote_bh,
        .go_drop_th = inode_go_drop_th,
-       .go_sync = inode_go_sync,
        .go_inval = inode_go_inval,
        .go_demote_ok = inode_go_demote_ok,
        .go_lock = inode_go_lock,
        .go_unlock = inode_go_unlock,
-       .go_greedy = inode_greedy,
        .go_type = LM_TYPE_INODE,
 };
 
 const struct gfs2_glock_operations gfs2_rgrp_glops = {
-       .go_xmote_th = gfs2_glock_xmote_th,
-       .go_drop_th = gfs2_glock_drop_th,
-       .go_sync = meta_go_sync,
        .go_inval = meta_go_inval,
        .go_demote_ok = rgrp_go_demote_ok,
        .go_lock = rgrp_go_lock,
@@ -515,33 +475,23 @@ const struct gfs2_glock_operations gfs2_trans_glops = {
 };
 
 const struct gfs2_glock_operations gfs2_iopen_glops = {
-       .go_xmote_th = gfs2_glock_xmote_th,
-       .go_drop_th = gfs2_glock_drop_th,
        .go_type = LM_TYPE_IOPEN,
 };
 
 const struct gfs2_glock_operations gfs2_flock_glops = {
-       .go_xmote_th = gfs2_glock_xmote_th,
-       .go_drop_th = gfs2_glock_drop_th,
        .go_type = LM_TYPE_FLOCK,
 };
 
 const struct gfs2_glock_operations gfs2_nondisk_glops = {
-       .go_xmote_th = gfs2_glock_xmote_th,
-       .go_drop_th = gfs2_glock_drop_th,
        .go_type = LM_TYPE_NONDISK,
 };
 
 const struct gfs2_glock_operations gfs2_quota_glops = {
-       .go_xmote_th = gfs2_glock_xmote_th,
-       .go_drop_th = gfs2_glock_drop_th,
        .go_demote_ok = quota_go_demote_ok,
        .go_type = LM_TYPE_QUOTA,
 };
 
 const struct gfs2_glock_operations gfs2_journal_glops = {
-       .go_xmote_th = gfs2_glock_xmote_th,
-       .go_drop_th = gfs2_glock_drop_th,
        .go_type = LM_TYPE_JOURNAL,
 };
 
index 734421e..12c80fd 100644 (file)
@@ -101,17 +101,14 @@ struct gfs2_bufdata {
 };
 
 struct gfs2_glock_operations {
-       void (*go_xmote_th) (struct gfs2_glock *gl, unsigned int state, int flags);
+       void (*go_xmote_th) (struct gfs2_glock *gl);
        void (*go_xmote_bh) (struct gfs2_glock *gl);
        void (*go_drop_th) (struct gfs2_glock *gl);
        void (*go_drop_bh) (struct gfs2_glock *gl);
-       void (*go_sync) (struct gfs2_glock *gl);
        void (*go_inval) (struct gfs2_glock *gl, int flags);
        int (*go_demote_ok) (struct gfs2_glock *gl);
        int (*go_lock) (struct gfs2_holder *gh);
        void (*go_unlock) (struct gfs2_holder *gh);
-       void (*go_callback) (struct gfs2_glock *gl, unsigned int state);
-       void (*go_greedy) (struct gfs2_glock *gl);
        const int go_type;
 };
 
@@ -120,7 +117,6 @@ enum {
        HIF_MUTEX               = 0,
        HIF_PROMOTE             = 1,
        HIF_DEMOTE              = 2,
-       HIF_GREEDY              = 3,
 
        /* States */
        HIF_ALLOCED             = 4,
@@ -128,6 +124,7 @@ enum {
        HIF_HOLDER              = 6,
        HIF_FIRST               = 7,
        HIF_ABORTED             = 9,
+       HIF_WAIT                = 10,
 };
 
 struct gfs2_holder {
@@ -140,17 +137,14 @@ struct gfs2_holder {
 
        int gh_error;
        unsigned long gh_iflags;
-       struct completion gh_wait;
        unsigned long gh_ip;
 };
 
 enum {
        GLF_LOCK                = 1,
        GLF_STICKY              = 2,
-       GLF_PREFETCH            = 3,
        GLF_DIRTY               = 5,
        GLF_SKIP_WAITERS2       = 6,
-       GLF_GREEDY              = 7,
 };
 
 struct gfs2_glock {
@@ -167,7 +161,7 @@ struct gfs2_glock {
        unsigned long gl_ip;
        struct list_head gl_holders;
        struct list_head gl_waiters1;   /* HIF_MUTEX */
-       struct list_head gl_waiters2;   /* HIF_DEMOTE, HIF_GREEDY */
+       struct list_head gl_waiters2;   /* HIF_DEMOTE */
        struct list_head gl_waiters3;   /* HIF_PROMOTE */
 
        const struct gfs2_glock_operations *gl_ops;
@@ -236,7 +230,6 @@ struct gfs2_inode {
 
        spinlock_t i_spin;
        struct rw_semaphore i_rw_mutex;
-       unsigned int i_greedy;
        unsigned long i_last_pfault;
 
        struct buffer_head *i_cache[GFS2_MAX_META_HEIGHT];
@@ -418,17 +411,12 @@ struct gfs2_tune {
        unsigned int gt_atime_quantum; /* Min secs between atime updates */
        unsigned int gt_new_files_jdata;
        unsigned int gt_new_files_directio;
-       unsigned int gt_max_atomic_write; /* Split big writes into this size */
        unsigned int gt_max_readahead; /* Max bytes to read-ahead from disk */
        unsigned int gt_lockdump_size;
        unsigned int gt_stall_secs; /* Detects trouble! */
        unsigned int gt_complain_secs;
        unsigned int gt_reclaim_limit; /* Max num of glocks in reclaim list */
        unsigned int gt_entries_per_readdir;
-       unsigned int gt_prefetch_secs; /* Usage window for prefetched glocks */
-       unsigned int gt_greedy_default;
-       unsigned int gt_greedy_quantum;
-       unsigned int gt_greedy_max;
        unsigned int gt_statfs_quantum;
        unsigned int gt_statfs_slow;
 };
index d122074..0d6831a 100644 (file)
@@ -287,10 +287,8 @@ out:
  *
  * Returns: errno
  */
-
 int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
 {
-       struct gfs2_sbd *sdp = ip->i_inode.i_sb->s_fs_info;
        struct buffer_head *dibh;
        u32 nlink;
        int error;
@@ -315,42 +313,34 @@ int gfs2_change_nlink(struct gfs2_inode *ip, int diff)
        else
                drop_nlink(&ip->i_inode);
 
-       ip->i_inode.i_ctime.tv_sec = get_seconds();
+       ip->i_inode.i_ctime = CURRENT_TIME_SEC;
 
        gfs2_trans_add_bh(ip->i_gl, dibh, 1);
        gfs2_dinode_out(ip, dibh->b_data);
        brelse(dibh);
        mark_inode_dirty(&ip->i_inode);
 
-       if (ip->i_inode.i_nlink == 0) {
-               struct gfs2_rgrpd *rgd;
-               struct gfs2_holder ri_gh, rg_gh;
-
-               error = gfs2_rindex_hold(sdp, &ri_gh);
-               if (error)
-                       goto out;
-               error = -EIO;
-               rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
-               if (!rgd)
-                       goto out_norgrp;
-               error = gfs2_glock_nq_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, &rg_gh);
-               if (error)
-                       goto out_norgrp;
-
+       if (ip->i_inode.i_nlink == 0)
                gfs2_unlink_di(&ip->i_inode); /* mark inode unlinked */
-               gfs2_glock_dq_uninit(&rg_gh);
-out_norgrp:
-               gfs2_glock_dq_uninit(&ri_gh);
-       }
-out:
+
        return error;
 }
 
 struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
 {
        struct qstr qstr;
+       struct inode *inode;
        gfs2_str2qstr(&qstr, name);
-       return gfs2_lookupi(dip, &qstr, 1, NULL);
+       inode = gfs2_lookupi(dip, &qstr, 1, NULL);
+       /* gfs2_lookupi has inconsistent callers: vfs
+        * related routines expect NULL for no entry found,
+        * gfs2_lookup_simple callers expect ENOENT
+        * and do not check for NULL.
+        */
+       if (inode == NULL)
+               return ERR_PTR(-ENOENT);
+       else
+               return inode;
 }
 
 
@@ -361,8 +351,10 @@ struct inode *gfs2_lookup_simple(struct inode *dip, const char *name)
  * @is_root: If 1, ignore the caller's permissions
  * @i_gh: An uninitialized holder for the new inode glock
  *
- * There will always be a vnode (Linux VFS inode) for the d_gh inode unless
- * @is_root is true.
+ * This can be called via the VFS filldir function when NFS is doing
+ * a readdirplus and the inode which its intending to stat isn't
+ * already in cache. In this case we must not take the directory glock
+ * again, since the readdir call will have already taken that lock.
  *
  * Returns: errno
  */
@@ -375,8 +367,9 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
        struct gfs2_holder d_gh;
        struct gfs2_inum_host inum;
        unsigned int type;
-       int error = 0;
+       int error;
        struct inode *inode = NULL;
+       int unlock = 0;
 
        if (!name->len || name->len > GFS2_FNAMESIZE)
                return ERR_PTR(-ENAMETOOLONG);
@@ -388,9 +381,12 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
                return dir;
        }
 
-       error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
-       if (error)
-               return ERR_PTR(error);
+       if (gfs2_glock_is_locked_by_me(dip->i_gl) == 0) {
+               error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
+               if (error)
+                       return ERR_PTR(error);
+               unlock = 1;
+       }
 
        if (!is_root) {
                error = permission(dir, MAY_EXEC, NULL);
@@ -405,10 +401,11 @@ struct inode *gfs2_lookupi(struct inode *dir, const struct qstr *name,
        inode = gfs2_inode_lookup(sb, &inum, type);
 
 out:
-       gfs2_glock_dq_uninit(&d_gh);
+       if (unlock)
+               gfs2_glock_dq_uninit(&d_gh);
        if (error == -ENOENT)
                return NULL;
-       return inode;
+       return inode ? inode : ERR_PTR(error);
 }
 
 static int pick_formal_ino_1(struct gfs2_sbd *sdp, u64 *formal_ino)
index effe4a3..e30673d 100644 (file)
@@ -104,15 +104,9 @@ int gfs2_lm_withdraw(struct gfs2_sbd *sdp, char *fmt, ...)
        vprintk(fmt, args);
        va_end(args);
 
-       fs_err(sdp, "about to withdraw from the cluster\n");
+       fs_err(sdp, "about to withdraw this file system\n");
        BUG_ON(sdp->sd_args.ar_debug);
 
-
-       fs_err(sdp, "waiting for outstanding I/O\n");
-
-       /* FIXME: suspend dm device so oustanding bio's complete
-          and all further io requests fail */
-
        fs_err(sdp, "telling LM to withdraw\n");
        gfs2_withdraw_lockproto(&sdp->sd_lockstruct);
        fs_err(sdp, "withdrawn\n");
index 33af707..a87c7bf 100644 (file)
@@ -36,7 +36,7 @@
 
 #define GDLM_STRNAME_BYTES     24
 #define GDLM_LVB_SIZE          32
-#define GDLM_DROP_COUNT                50000
+#define GDLM_DROP_COUNT                200000
 #define GDLM_DROP_PERIOD       60
 #define GDLM_NAME_LEN          128
 
index 2194b1d..a0e7eda 100644 (file)
@@ -11,9 +11,6 @@
 
 #include "lock_dlm.h"
 
-extern int gdlm_drop_count;
-extern int gdlm_drop_period;
-
 extern struct lm_lockops gdlm_ops;
 
 static int __init init_lock_dlm(void)
@@ -40,9 +37,6 @@ static int __init init_lock_dlm(void)
                return error;
        }
 
-       gdlm_drop_count = GDLM_DROP_COUNT;
-       gdlm_drop_period = GDLM_DROP_PERIOD;
-
        printk(KERN_INFO
               "Lock_DLM (built %s %s) installed\n", __DATE__, __TIME__);
        return 0;
index cdd1694..1d8faa3 100644 (file)
@@ -9,8 +9,6 @@
 
 #include "lock_dlm.h"
 
-int gdlm_drop_count;
-int gdlm_drop_period;
 const struct lm_lockops gdlm_ops;
 
 
@@ -24,8 +22,8 @@ static struct gdlm_ls *init_gdlm(lm_callback_t cb, struct gfs2_sbd *sdp,
        if (!ls)
                return NULL;
 
-       ls->drop_locks_count = gdlm_drop_count;
-       ls->drop_locks_period = gdlm_drop_period;
+       ls->drop_locks_count = GDLM_DROP_COUNT;
+       ls->drop_locks_period = GDLM_DROP_PERIOD;
        ls->fscb = cb;
        ls->sdp = sdp;
        ls->fsflags = flags;
index 29ae06f..4746b88 100644 (file)
@@ -116,6 +116,17 @@ static ssize_t recover_status_show(struct gdlm_ls *ls, char *buf)
        return sprintf(buf, "%d\n", ls->recover_jid_status);
 }
 
+static ssize_t drop_count_show(struct gdlm_ls *ls, char *buf)
+{
+       return sprintf(buf, "%d\n", ls->drop_locks_count);
+}
+
+static ssize_t drop_count_store(struct gdlm_ls *ls, const char *buf, size_t len)
+{
+       ls->drop_locks_count = simple_strtol(buf, NULL, 0);
+       return len;
+}
+
 struct gdlm_attr {
        struct attribute attr;
        ssize_t (*show)(struct gdlm_ls *, char *);
@@ -135,6 +146,7 @@ GDLM_ATTR(first_done,     0444, first_done_show,     NULL);
 GDLM_ATTR(recover,        0644, recover_show,        recover_store);
 GDLM_ATTR(recover_done,   0444, recover_done_show,   NULL);
 GDLM_ATTR(recover_status, 0444, recover_status_show, NULL);
+GDLM_ATTR(drop_count,     0644, drop_count_show,     drop_count_store);
 
 static struct attribute *gdlm_attrs[] = {
        &gdlm_attr_proto_name.attr,
@@ -147,6 +159,7 @@ static struct attribute *gdlm_attrs[] = {
        &gdlm_attr_recover.attr,
        &gdlm_attr_recover_done.attr,
        &gdlm_attr_recover_status.attr,
+       &gdlm_attr_drop_count.attr,
        NULL,
 };
 
index 4d7f94d..16bb4b4 100644 (file)
@@ -69,13 +69,16 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
        struct gfs2_bufdata *bd = container_of(le, struct gfs2_bufdata, bd_le);
        struct gfs2_trans *tr;
 
-       if (!list_empty(&bd->bd_list_tr))
+       gfs2_log_lock(sdp);
+       if (!list_empty(&bd->bd_list_tr)) {
+               gfs2_log_unlock(sdp);
                return;
-
+       }
        tr = current->journal_info;
        tr->tr_touched = 1;
        tr->tr_num_buf++;
        list_add(&bd->bd_list_tr, &tr->tr_list_buf);
+       gfs2_log_unlock(sdp);
 
        if (!list_empty(&le->le_list))
                return;
@@ -84,7 +87,6 @@ static void buf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
 
        gfs2_meta_check(sdp, bd->bd_bh);
        gfs2_pin(sdp, bd->bd_bh);
-
        gfs2_log_lock(sdp);
        sdp->sd_log_num_buf++;
        list_add(&le->le_list, &sdp->sd_log_le_buf);
@@ -98,11 +100,13 @@ static void buf_lo_incore_commit(struct gfs2_sbd *sdp, struct gfs2_trans *tr)
        struct list_head *head = &tr->tr_list_buf;
        struct gfs2_bufdata *bd;
 
+       gfs2_log_lock(sdp);
        while (!list_empty(head)) {
                bd = list_entry(head->next, struct gfs2_bufdata, bd_list_tr);
                list_del_init(&bd->bd_list_tr);
                tr->tr_num_buf--;
        }
+       gfs2_log_unlock(sdp);
        gfs2_assert_warn(sdp, !tr->tr_num_buf);
 }
 
@@ -462,13 +466,17 @@ static void databuf_lo_add(struct gfs2_sbd *sdp, struct gfs2_log_element *le)
        struct address_space *mapping = bd->bd_bh->b_page->mapping;
        struct gfs2_inode *ip = GFS2_I(mapping->host);
 
+       gfs2_log_lock(sdp);
        tr->tr_touched = 1;
        if (list_empty(&bd->bd_list_tr) &&
            (ip->i_di.di_flags & GFS2_DIF_JDATA)) {
                tr->tr_num_buf++;
                list_add(&bd->bd_list_tr, &tr->tr_list_buf);
+               gfs2_log_unlock(sdp);
                gfs2_pin(sdp, bd->bd_bh);
                tr->tr_num_buf_new++;
+       } else {
+               gfs2_log_unlock(sdp);
        }
        gfs2_trans_add_gl(bd->bd_gl);
        gfs2_log_lock(sdp);
index d8d69a7..56e3359 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/pagevec.h>
 #include <linux/mpage.h>
 #include <linux/fs.h>
+#include <linux/writeback.h>
 #include <linux/gfs2_ondisk.h>
 #include <linux/lm_interface.h>
 
@@ -156,6 +157,32 @@ out_ignore:
        return 0;
 }
 
+/**
+ * gfs2_writepages - Write a bunch of dirty pages back to disk
+ * @mapping: The mapping to write
+ * @wbc: Write-back control
+ *
+ * For journaled files and/or ordered writes this just falls back to the
+ * kernel's default writepages path for now. We will probably want to change
+ * that eventually (i.e. when we look at allocate on flush).
+ *
+ * For the data=writeback case though we can already ignore buffer heads
+ * and write whole extents at once. This is a big reduction in the
+ * number of I/O requests we send and the bmap calls we make in this case.
+ */
+static int gfs2_writepages(struct address_space *mapping,
+                          struct writeback_control *wbc)
+{
+       struct inode *inode = mapping->host;
+       struct gfs2_inode *ip = GFS2_I(inode);
+       struct gfs2_sbd *sdp = GFS2_SB(inode);
+
+       if (sdp->sd_args.ar_data == GFS2_DATA_WRITEBACK && !gfs2_is_jdata(ip))
+               return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
+
+       return generic_writepages(mapping, wbc);
+}
+
 /**
  * stuffed_readpage - Fill in a Linux page with stuffed file data
  * @ip: the inode
@@ -256,7 +283,7 @@ out_unlock:
  *    the page lock and the glock) and return having done no I/O. Its
  *    obviously not something we'd want to do on too regular a basis.
  *    Any I/O we ignore at this time will be done via readpage later.
- * 2. We have to handle stuffed files here too.
+ * 2. We don't handle stuffed files here we let readpage do the honours.
  * 3. mpage_readpages() does most of the heavy lifting in the common case.
  * 4. gfs2_get_block() is relied upon to set BH_Boundary in the right places.
  * 5. We use LM_FLAG_TRY_1CB here, effectively we then have lock-ahead as
@@ -269,8 +296,7 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping,
        struct gfs2_inode *ip = GFS2_I(inode);
        struct gfs2_sbd *sdp = GFS2_SB(inode);
        struct gfs2_holder gh;
-       unsigned page_idx;
-       int ret;
+       int ret = 0;
        int do_unlock = 0;
 
        if (likely(file != &gfs2_internal_file_sentinel)) {
@@ -289,29 +315,8 @@ static int gfs2_readpages(struct file *file, struct address_space *mapping,
                        goto out_unlock;
        }
 skip_lock:
-       if (gfs2_is_stuffed(ip)) {
-               struct pagevec lru_pvec;
-               pagevec_init(&lru_pvec, 0);
-               for (page_idx = 0; page_idx < nr_pages; page_idx++) {
-                       struct page *page = list_entry(pages->prev, struct page, lru);
-                       prefetchw(&page->flags);
-                       list_del(&page->lru);
-                       if (!add_to_page_cache(page, mapping,
-                                              page->index, GFP_KERNEL)) {
-                               ret = stuffed_readpage(ip, page);
-                               unlock_page(page);
-                               if (!pagevec_add(&lru_pvec, page))
-                                        __pagevec_lru_add(&lru_pvec);
-                       } else {
-                               page_cache_release(page);
-                       }
-               }
-               pagevec_lru_add(&lru_pvec);
-               ret = 0;
-       } else {
-               /* What we really want to do .... */
+       if (!gfs2_is_stuffed(ip))
                ret = mpage_readpages(mapping, pages, nr_pages, gfs2_get_block);
-       }
 
        if (do_unlock) {
                gfs2_glock_dq_m(1, &gh);
@@ -356,8 +361,10 @@ static int gfs2_prepare_write(struct file *file, struct page *page,
        gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, GL_ATIME|LM_FLAG_TRY_1CB, &ip->i_gh);
        error = gfs2_glock_nq_atime(&ip->i_gh);
        if (unlikely(error)) {
-               if (error == GLR_TRYFAILED)
+               if (error == GLR_TRYFAILED) {
+                       unlock_page(page);
                        error = AOP_TRUNCATED_PAGE;
+               }
                goto out_uninit;
        }
 
@@ -594,6 +601,36 @@ static void gfs2_invalidatepage(struct page *page, unsigned long offset)
        return;
 }
 
+/**
+ * gfs2_ok_for_dio - check that dio is valid on this file
+ * @ip: The inode
+ * @rw: READ or WRITE
+ * @offset: The offset at which we are reading or writing
+ *
+ * Returns: 0 (to ignore the i/o request and thus fall back to buffered i/o)
+ *          1 (to accept the i/o request)
+ */
+static int gfs2_ok_for_dio(struct gfs2_inode *ip, int rw, loff_t offset)
+{
+       /*
+        * Should we return an error here? I can't see that O_DIRECT for
+        * a journaled file makes any sense. For now we'll silently fall
+        * back to buffered I/O, likewise we do the same for stuffed
+        * files since they are (a) small and (b) unaligned.
+        */
+       if (gfs2_is_jdata(ip))
+               return 0;
+
+       if (gfs2_is_stuffed(ip))
+               return 0;
+
+       if (offset > i_size_read(&ip->i_inode))
+               return 0;
+       return 1;
+}
+
+
+
 static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
                              const struct iovec *iov, loff_t offset,
                              unsigned long nr_segs)
@@ -604,42 +641,28 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb,
        struct gfs2_holder gh;
        int rv;
 
-       if (rw == READ)
-               mutex_lock(&inode->i_mutex);
        /*
-        * Shared lock, even if its a write, since we do no allocation
-        * on this path. All we need change is atime.
+        * Deferred lock, even if its a write, since we do no allocation
+        * on this path. All we need change is atime, and this lock mode
+        * ensures that other nodes have flushed their buffered read caches
+        * (i.e. their page cache entries for this inode). We do not,
+        * unfortunately have the option of only flushing a range like
+        * the VFS does.
         */
-       gfs2_holder_init(ip->i_gl, LM_ST_SHARED, GL_ATIME, &gh);
+       gfs2_holder_init(ip->i_gl, LM_ST_DEFERRED, GL_ATIME, &gh);
        rv = gfs2_glock_nq_atime(&gh);
        if (rv)
-               goto out;
-
-       if (offset > i_size_read(inode))
-               goto out;
-
-       /*
-        * Should we return an error here? I can't see that O_DIRECT for
-        * a journaled file makes any sense. For now we'll silently fall
-        * back to buffered I/O, likewise we do the same for stuffed
-        * files since they are (a) small and (b) unaligned.
-        */
-       if (gfs2_is_jdata(ip))
-               goto out;
-
-       if (gfs2_is_stuffed(ip))
-               goto out;
-
-       rv = blockdev_direct_IO_own_locking(rw, iocb, inode,
-                                           inode->i_sb->s_bdev,
-                                           iov, offset, nr_segs,
-                                           gfs2_get_block_direct, NULL);
+               return rv;
+       rv = gfs2_ok_for_dio(ip, rw, offset);
+       if (rv != 1)
+               goto out; /* dio not valid, fall back to buffered i/o */
+
+       rv = blockdev_direct_IO_no_locking(rw, iocb, inode, inode->i_sb->s_bdev,
+                                          iov, offset, nr_segs,
+                                          gfs2_get_block_direct, NULL);
 out:
        gfs2_glock_dq_m(1, &gh);
        gfs2_holder_uninit(&gh);
-       if (rw == READ)
-               mutex_unlock(&inode->i_mutex);
-
        return rv;
 }
 
@@ -763,6 +786,7 @@ out:
 
 const struct address_space_operations gfs2_file_aops = {
        .writepage = gfs2_writepage,
+       .writepages = gfs2_writepages,
        .readpage = gfs2_readpage,
        .readpages = gfs2_readpages,
        .sync_page = block_sync_page,
index d355899..9187eb1 100644 (file)
@@ -46,6 +46,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
        struct gfs2_inum_host inum;
        unsigned int type;
        int error;
+       int had_lock=0;
 
        if (inode && is_bad_inode(inode))
                goto invalid;
@@ -53,9 +54,12 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
        if (sdp->sd_args.ar_localcaching)
                goto valid;
 
-       error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
-       if (error)
-               goto fail;
+       had_lock = gfs2_glock_is_locked_by_me(dip->i_gl);
+       if (!had_lock) {
+               error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
+               if (error)
+                       goto fail;
+       } 
 
        error = gfs2_dir_search(parent->d_inode, &dentry->d_name, &inum, &type);
        switch (error) {
@@ -82,13 +86,15 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
        }
 
 valid_gunlock:
-       gfs2_glock_dq_uninit(&d_gh);
+       if (!had_lock)
+               gfs2_glock_dq_uninit(&d_gh);
 valid:
        dput(parent);
        return 1;
 
 invalid_gunlock:
-       gfs2_glock_dq_uninit(&d_gh);
+       if (!had_lock)
+               gfs2_glock_dq_uninit(&d_gh);
 invalid:
        if (inode && S_ISDIR(inode->i_mode)) {
                if (have_submounts(dentry))
index b4e7b87..4855e8c 100644 (file)
@@ -22,6 +22,7 @@
 #include "glock.h"
 #include "glops.h"
 #include "inode.h"
+#include "ops_dentry.h"
 #include "ops_export.h"
 #include "rgrp.h"
 #include "util.h"
@@ -112,13 +113,12 @@ struct get_name_filldir {
        char *name;
 };
 
-static int get_name_filldir(void *opaque, const char *name, unsigned int length,
-                           u64 offset, struct gfs2_inum_host *inum,
-                           unsigned int type)
+static int get_name_filldir(void *opaque, const char *name, int length,
+                           loff_t offset, u64 inum, unsigned int type)
 {
-       struct get_name_filldir *gnfd = (struct get_name_filldir *)opaque;
+       struct get_name_filldir *gnfd = opaque;
 
-       if (!gfs2_inum_equal(inum, &gnfd->inum))
+       if (inum != gnfd->inum.no_addr)
                return 0;
 
        memcpy(gnfd->name, name, length);
@@ -189,6 +189,7 @@ static struct dentry *gfs2_get_parent(struct dentry *child)
                return ERR_PTR(-ENOMEM);
        }
 
+       dentry->d_op = &gfs2_dops;
        return dentry;
 }
 
@@ -215,8 +216,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, void *inum_obj)
        }
 
        error = gfs2_glock_nq_num(sdp, inum->no_addr, &gfs2_inode_glops,
-                                 LM_ST_SHARED, LM_FLAG_ANY | GL_LOCAL_EXCL,
-                                 &i_gh);
+                                 LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
        if (error)
                return ERR_PTR(error);
 
@@ -269,6 +269,7 @@ out_inode:
                return ERR_PTR(-ENOMEM);
        }
 
+       dentry->d_op = &gfs2_dops;
        return dentry;
 
 fail_rgd:
index faa07e4..c996aa7 100644 (file)
 #include "util.h"
 #include "eaops.h"
 
-/* For regular, non-NFS */
-struct filldir_reg {
-       struct gfs2_sbd *fdr_sbd;
-       int fdr_prefetch;
-
-       filldir_t fdr_filldir;
-       void *fdr_opaque;
-};
-
 /*
  * Most fields left uninitialised to catch anybody who tries to
  * use them. f_flags set to prevent file_accessed() from touching
@@ -127,41 +118,6 @@ static loff_t gfs2_llseek(struct file *file, loff_t offset, int origin)
        return error;
 }
 
-/**
- * filldir_func - Report a directory entry to the caller of gfs2_dir_read()
- * @opaque: opaque data used by the function
- * @name: the name of the directory entry
- * @length: the length of the name
- * @offset: the entry's offset in the directory
- * @inum: the inode number the entry points to
- * @type: the type of inode the entry points to
- *
- * Returns: 0 on success, 1 if buffer full
- */
-
-static int filldir_func(void *opaque, const char *name, unsigned int length,
-                       u64 offset, struct gfs2_inum_host *inum,
-                       unsigned int type)
-{
-       struct filldir_reg *fdr = (struct filldir_reg *)opaque;
-       struct gfs2_sbd *sdp = fdr->fdr_sbd;
-       int error;
-
-       error = fdr->fdr_filldir(fdr->fdr_opaque, name, length, offset,
-                                inum->no_addr, type);
-       if (error)
-               return 1;
-
-       if (fdr->fdr_prefetch && !(length == 1 && *name == '.')) {
-               gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_inode_glops,
-                                      LM_ST_SHARED, LM_FLAG_TRY | LM_FLAG_ANY);
-               gfs2_glock_prefetch_num(sdp, inum->no_addr, &gfs2_iopen_glops,
-                                      LM_ST_SHARED, LM_FLAG_TRY);
-       }
-
-       return 0;
-}
-
 /**
  * gfs2_readdir - Read directory entries from a directory
  * @file: The directory to read from
@@ -175,16 +131,10 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir)
 {
        struct inode *dir = file->f_mapping->host;
        struct gfs2_inode *dip = GFS2_I(dir);
-       struct filldir_reg fdr;
        struct gfs2_holder d_gh;
        u64 offset = file->f_pos;
        int error;
 
-       fdr.fdr_sbd = GFS2_SB(dir);
-       fdr.fdr_prefetch = 1;
-       fdr.fdr_filldir = filldir;
-       fdr.fdr_opaque = dirent;
-
        gfs2_holder_init(dip->i_gl, LM_ST_SHARED, GL_ATIME, &d_gh);
        error = gfs2_glock_nq_atime(&d_gh);
        if (error) {
@@ -192,7 +142,7 @@ static int gfs2_readdir(struct file *file, void *dirent, filldir_t filldir)
                return error;
        }
 
-       error = gfs2_dir_read(dir, &offset, &fdr, filldir_func);
+       error = gfs2_dir_read(dir, &offset, dirent, filldir);
 
        gfs2_glock_dq_uninit(&d_gh);
 
index 636dda4..f40a848 100644 (file)
@@ -264,13 +264,23 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
        struct gfs2_inode *dip = GFS2_I(dir);
        struct gfs2_sbd *sdp = GFS2_SB(dir);
        struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
-       struct gfs2_holder ghs[2];
+       struct gfs2_holder ghs[3];
+       struct gfs2_rgrpd *rgd;
+       struct gfs2_holder ri_gh;
        int error;
 
+       error = gfs2_rindex_hold(sdp, &ri_gh);
+       if (error)
+               return error;
+
        gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
-       gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
+       gfs2_holder_init(ip->i_gl,  LM_ST_EXCLUSIVE, 0, ghs + 1);
 
-       error = gfs2_glock_nq_m(2, ghs);
+       rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
+       gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);
+
+
+       error = gfs2_glock_nq_m(3, ghs);
        if (error)
                goto out;
 
@@ -291,10 +301,12 @@ static int gfs2_unlink(struct inode *dir, struct dentry *dentry)
 out_end_trans:
        gfs2_trans_end(sdp);
 out_gunlock:
-       gfs2_glock_dq_m(2, ghs);
+       gfs2_glock_dq_m(3, ghs);
 out:
        gfs2_holder_uninit(ghs);
        gfs2_holder_uninit(ghs + 1);
+       gfs2_holder_uninit(ghs + 2);
+       gfs2_glock_dq_uninit(&ri_gh);
        return error;
 }
 
@@ -449,13 +461,22 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry)
        struct gfs2_inode *dip = GFS2_I(dir);
        struct gfs2_sbd *sdp = GFS2_SB(dir);
        struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
-       struct gfs2_holder ghs[2];
+       struct gfs2_holder ghs[3];
+       struct gfs2_rgrpd *rgd;
+       struct gfs2_holder ri_gh;
        int error;
 
+
+       error = gfs2_rindex_hold(sdp, &ri_gh);
+       if (error)
+               return error;
        gfs2_holder_init(dip->i_gl, LM_ST_EXCLUSIVE, 0, ghs);
        gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + 1);
 
-       error = gfs2_glock_nq_m(2, ghs);
+       rgd = gfs2_blk2rgrpd(sdp, ip->i_num.no_addr);
+       gfs2_holder_init(rgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + 2);
+
+       error = gfs2_glock_nq_m(3, ghs);
        if (error)
                goto out;
 
@@ -483,10 +504,12 @@ static int gfs2_rmdir(struct inode *dir, struct dentry *dentry)
        gfs2_trans_end(sdp);
 
 out_gunlock:
-       gfs2_glock_dq_m(2, ghs);
+       gfs2_glock_dq_m(3, ghs);
 out:
        gfs2_holder_uninit(ghs);
        gfs2_holder_uninit(ghs + 1);
+       gfs2_holder_uninit(ghs + 2);
+       gfs2_glock_dq_uninit(&ri_gh);
        return error;
 }
 
@@ -547,7 +570,8 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
        struct gfs2_inode *ip = GFS2_I(odentry->d_inode);
        struct gfs2_inode *nip = NULL;
        struct gfs2_sbd *sdp = GFS2_SB(odir);
-       struct gfs2_holder ghs[4], r_gh;
+       struct gfs2_holder ghs[5], r_gh;
+       struct gfs2_rgrpd *nrgd;
        unsigned int num_gh;
        int dir_rename = 0;
        int alloc_required;
@@ -587,6 +611,13 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
        if (nip) {
                gfs2_holder_init(nip->i_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh);
                num_gh++;
+               /* grab the resource lock for unlink flag twiddling 
+                * this is the case of the target file already existing
+                * so we unlink before doing the rename
+                */
+               nrgd = gfs2_blk2rgrpd(sdp, nip->i_num.no_addr);
+               if (nrgd)
+                       gfs2_holder_init(nrgd->rd_gl, LM_ST_EXCLUSIVE, 0, ghs + num_gh++);
        }
 
        error = gfs2_glock_nq_m(num_gh, ghs);
@@ -684,12 +715,12 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
                error = gfs2_trans_begin(sdp, sdp->sd_max_dirres +
                                         al->al_rgd->rd_ri.ri_length +
                                         4 * RES_DINODE + 4 * RES_LEAF +
-                                        RES_STATFS + RES_QUOTA, 0);
+                                        RES_STATFS + RES_QUOTA + 4, 0);
                if (error)
                        goto out_ipreserv;
        } else {
                error = gfs2_trans_begin(sdp, 4 * RES_DINODE +
-                                        5 * RES_LEAF, 0);
+                                        5 * RES_LEAF + 4, 0);
                if (error)
                        goto out_gunlock;
        }
@@ -728,7 +759,7 @@ static int gfs2_rename(struct inode *odir, struct dentry *odentry,
                error = gfs2_meta_inode_buffer(ip, &dibh);
                if (error)
                        goto out_end_trans;
-               ip->i_inode.i_ctime.tv_sec = get_seconds();
+               ip->i_inode.i_ctime = CURRENT_TIME_SEC;
                gfs2_trans_add_bh(ip->i_gl, dibh, 1);
                gfs2_dinode_out(ip, dibh->b_data);
                brelse(dibh);
@@ -1018,7 +1049,7 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
        }
 
        generic_fillattr(inode, stat);
-       if (unlock);
+       if (unlock)
                gfs2_glock_dq_uninit(&gh);
 
        return 0;
index 7685b46..47369d0 100644 (file)
@@ -173,6 +173,9 @@ static void gfs2_write_super_lockfs(struct super_block *sb)
        struct gfs2_sbd *sdp = sb->s_fs_info;
        int error;
 
+       if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
+               return;
+
        for (;;) {
                error = gfs2_freeze_fs(sdp);
                if (!error)
@@ -426,6 +429,12 @@ static void gfs2_delete_inode(struct inode *inode)
        }
 
        error = gfs2_dinode_dealloc(ip);
+       /*
+        * Must do this before unlock to avoid trying to write back
+        * potentially dirty data now that inode no longer exists
+        * on disk.
+        */
+       truncate_inode_pages(&inode->i_data, 0);
 
 out_unlock:
        gfs2_glock_dq(&ip->i_iopen_gh);
@@ -443,14 +452,12 @@ out:
 
 static struct inode *gfs2_alloc_inode(struct super_block *sb)
 {
-       struct gfs2_sbd *sdp = sb->s_fs_info;
        struct gfs2_inode *ip;
 
        ip = kmem_cache_alloc(gfs2_inode_cachep, GFP_KERNEL);
        if (ip) {
                ip->i_flags = 0;
                ip->i_gl = NULL;
-               ip->i_greedy = gfs2_tune_get(sdp, gt_greedy_default);
                ip->i_last_pfault = jiffies;
        }
        return &ip->i_inode;
index 45a5f11..14b380f 100644 (file)
 #include "trans.h"
 #include "util.h"
 
-static void pfault_be_greedy(struct gfs2_inode *ip)
-{
-       unsigned int time;
-
-       spin_lock(&ip->i_spin);
-       time = ip->i_greedy;
-       ip->i_last_pfault = jiffies;
-       spin_unlock(&ip->i_spin);
-
-       igrab(&ip->i_inode);
-       if (gfs2_glock_be_greedy(ip->i_gl, time))
-               iput(&ip->i_inode);
-}
-
 static struct page *gfs2_private_nopage(struct vm_area_struct *area,
                                        unsigned long address, int *type)
 {
        struct gfs2_inode *ip = GFS2_I(area->vm_file->f_mapping->host);
-       struct page *result;
 
        set_bit(GIF_PAGED, &ip->i_flags);
-
-       result = filemap_nopage(area, address, type);
-
-       if (result && result != NOPAGE_OOM)
-               pfault_be_greedy(ip);
-
-       return result;
+       return filemap_nopage(area, address, type);
 }
 
 static int alloc_page_backing(struct gfs2_inode *ip, struct page *page)
@@ -167,7 +146,6 @@ static struct page *gfs2_sharewrite_nopage(struct vm_area_struct *area,
                set_page_dirty(result);
        }
 
-       pfault_be_greedy(ip);
 out:
        gfs2_glock_dq_uninit(&i_gh);
 
index 43a24f2..70f424f 100644 (file)
@@ -71,17 +71,12 @@ void gfs2_tune_init(struct gfs2_tune *gt)
        gt->gt_atime_quantum = 3600;
        gt->gt_new_files_jdata = 0;
        gt->gt_new_files_directio = 0;
-       gt->gt_max_atomic_write = 4 << 20;
        gt->gt_max_readahead = 1 << 18;
        gt->gt_lockdump_size = 131072;
        gt->gt_stall_secs = 600;
        gt->gt_complain_secs = 10;
        gt->gt_reclaim_limit = 5000;
        gt->gt_entries_per_readdir = 32;
-       gt->gt_prefetch_secs = 10;
-       gt->gt_greedy_default = HZ / 10;
-       gt->gt_greedy_quantum = HZ / 40;
-       gt->gt_greedy_max = HZ / 4;
        gt->gt_statfs_quantum = 30;
        gt->gt_statfs_slow = 0;
 }
@@ -359,8 +354,7 @@ int gfs2_jindex_hold(struct gfs2_sbd *sdp, struct gfs2_holder *ji_gh)
        mutex_lock(&sdp->sd_jindex_mutex);
 
        for (;;) {
-               error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED,
-                                          GL_LOCAL_EXCL, ji_gh);
+               error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, ji_gh);
                if (error)
                        break;
 
@@ -529,8 +523,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
        struct gfs2_log_header_host head;
        int error;
 
-       error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
-                                  GL_LOCAL_EXCL, &t_gh);
+       error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, 0, &t_gh);
        if (error)
                return error;
 
@@ -583,9 +576,8 @@ int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
        gfs2_quota_sync(sdp);
        gfs2_statfs_sync(sdp);
 
-       error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED,
-                               GL_LOCAL_EXCL | GL_NOCACHE,
-                               &t_gh);
+       error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE,
+                                  &t_gh);
        if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
                return error;
 
index 983eaf1..d01f9f0 100644 (file)
@@ -436,17 +436,12 @@ TUNE_ATTR(atime_quantum, 0);
 TUNE_ATTR(max_readahead, 0);
 TUNE_ATTR(complain_secs, 0);
 TUNE_ATTR(reclaim_limit, 0);
-TUNE_ATTR(prefetch_secs, 0);
 TUNE_ATTR(statfs_slow, 0);
 TUNE_ATTR(new_files_jdata, 0);
 TUNE_ATTR(new_files_directio, 0);
 TUNE_ATTR(quota_simul_sync, 1);
 TUNE_ATTR(quota_cache_secs, 1);
-TUNE_ATTR(max_atomic_write, 1);
 TUNE_ATTR(stall_secs, 1);
-TUNE_ATTR(greedy_default, 1);
-TUNE_ATTR(greedy_quantum, 1);
-TUNE_ATTR(greedy_max, 1);
 TUNE_ATTR(statfs_quantum, 1);
 TUNE_ATTR_DAEMON(scand_secs, scand_process);
 TUNE_ATTR_DAEMON(recoverd_secs, recoverd_process);
@@ -465,15 +460,10 @@ static struct attribute *tune_attrs[] = {
        &tune_attr_max_readahead.attr,
        &tune_attr_complain_secs.attr,
        &tune_attr_reclaim_limit.attr,
-       &tune_attr_prefetch_secs.attr,
        &tune_attr_statfs_slow.attr,
        &tune_attr_quota_simul_sync.attr,
        &tune_attr_quota_cache_secs.attr,
-       &tune_attr_max_atomic_write.attr,
        &tune_attr_stall_secs.attr,
-       &tune_attr_greedy_default.attr,
-       &tune_attr_greedy_quantum.attr,
-       &tune_attr_greedy_max.attr,
        &tune_attr_statfs_quantum.attr,
        &tune_attr_scand_secs.attr,
        &tune_attr_recoverd_secs.attr,
index f571911..e285022 100644 (file)
@@ -182,9 +182,9 @@ int jfs_get_block(struct inode *ip, sector_t lblock,
         * Take appropriate lock on inode
         */
        if (create)
-               IWRITE_LOCK(ip);
+               IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
        else
-               IREAD_LOCK(ip);
+               IREAD_LOCK(ip, RDWRLOCK_NORMAL);
 
        if (((lblock64 << ip->i_sb->s_blocksize_bits) < ip->i_size) &&
            (!xtLookup(ip, lblock64, xlen, &xflag, &xaddr, &xlen, 0)) &&
@@ -359,7 +359,7 @@ void jfs_truncate(struct inode *ip)
 
        nobh_truncate_page(ip->i_mapping, ip->i_size);
 
-       IWRITE_LOCK(ip);
+       IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
        jfs_truncate_nolock(ip, ip->i_size);
        IWRITE_UNLOCK(ip);
 }
index ddffbbd..7378798 100644 (file)
@@ -39,10 +39,6 @@ extern void jfs_proc_clean(void);
 /*
  *     assert with traditional printf/panic
  */
-#ifdef CONFIG_KERNEL_ASSERTS
-/* kgdb stuff */
-#define assert(p) KERNEL_ASSERT(#p, p)
-#else
 #define assert(p) do { \
        if (!(p)) {     \
                printk(KERN_CRIT "BUG at %s:%d assert(%s)\n",   \
@@ -50,7 +46,6 @@ extern void jfs_proc_clean(void);
                BUG();  \
        }               \
 } while (0)
-#endif
 
 /*
  *     debug ON
index 23546c8..82b0544 100644 (file)
@@ -337,7 +337,7 @@ int dbFree(struct inode *ip, s64 blkno, s64 nblocks)
        struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
        struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
 
-       IREAD_LOCK(ipbmap);
+       IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
 
        /* block to be freed better be within the mapsize. */
        if (unlikely((blkno == 0) || (blkno + nblocks > bmp->db_mapsize))) {
@@ -733,7 +733,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
         * allocation group size, try to allocate anywhere.
         */
        if (l2nb > bmp->db_agl2size) {
-               IWRITE_LOCK(ipbmap);
+               IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP);
 
                rc = dbAllocAny(bmp, nblocks, l2nb, results);
 
@@ -774,7 +774,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
         * the hint using a tiered strategy.
         */
        if (nblocks <= BPERDMAP) {
-               IREAD_LOCK(ipbmap);
+               IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
 
                /* get the buffer for the dmap containing the hint.
                 */
@@ -844,7 +844,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
        /* try to satisfy the allocation request with blocks within
         * the same allocation group as the hint.
         */
-       IWRITE_LOCK(ipbmap);
+       IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP);
        if ((rc = dbAllocAG(bmp, agno, nblocks, l2nb, results)) != -ENOSPC)
                goto write_unlock;
 
@@ -856,7 +856,7 @@ int dbAlloc(struct inode *ip, s64 hint, s64 nblocks, s64 * results)
         * Let dbNextAG recommend a preferred allocation group
         */
        agno = dbNextAG(ipbmap);
-       IWRITE_LOCK(ipbmap);
+       IWRITE_LOCK(ipbmap, RDWRLOCK_DMAP);
 
        /* Try to allocate within this allocation group.  if that fails, try to
         * allocate anywhere in the map.
@@ -900,7 +900,7 @@ int dbAllocExact(struct inode *ip, s64 blkno, int nblocks)
        s64 lblkno;
        struct metapage *mp;
 
-       IREAD_LOCK(ipbmap);
+       IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
 
        /*
         * validate extent request:
@@ -1050,7 +1050,7 @@ static int dbExtend(struct inode *ip, s64 blkno, s64 nblocks, s64 addnblocks)
         */
        extblkno = lastblkno + 1;
 
-       IREAD_LOCK(ipbmap);
+       IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
 
        /* better be within the file system */
        bmp = sbi->bmap;
@@ -3116,7 +3116,7 @@ int dbAllocBottomUp(struct inode *ip, s64 blkno, s64 nblocks)
        struct inode *ipbmap = JFS_SBI(ip->i_sb)->ipbmap;
        struct bmap *bmp = JFS_SBI(ip->i_sb)->bmap;
 
-       IREAD_LOCK(ipbmap);
+       IREAD_LOCK(ipbmap, RDWRLOCK_DMAP);
 
        /* block to be allocated better be within the mapsize. */
        ASSERT(nblocks <= bmp->db_mapsize - blkno);
index 53f63b4..aa5124b 100644 (file)
@@ -331,7 +331,7 @@ int diRead(struct inode *ip)
 
        /* read the iag */
        imap = JFS_IP(ipimap)->i_imap;
-       IREAD_LOCK(ipimap);
+       IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
        rc = diIAGRead(imap, iagno, &mp);
        IREAD_UNLOCK(ipimap);
        if (rc) {
@@ -920,7 +920,7 @@ int diFree(struct inode *ip)
        /* Obtain read lock in imap inode.  Don't release it until we have
         * read all of the IAG's that we are going to.
         */
-       IREAD_LOCK(ipimap);
+       IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
 
        /* read the iag.
         */
@@ -1415,7 +1415,7 @@ int diAlloc(struct inode *pip, bool dir, struct inode *ip)
        AG_LOCK(imap, agno);
 
        /* Get read lock on imap inode */
-       IREAD_LOCK(ipimap);
+       IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
 
        /* get the iag number and read the iag */
        iagno = INOTOIAG(inum);
@@ -1808,7 +1808,7 @@ static int diAllocIno(struct inomap * imap, int agno, struct inode *ip)
                return -ENOSPC;
 
        /* obtain read lock on imap inode */
-       IREAD_LOCK(imap->im_ipimap);
+       IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP);
 
        /* read the iag at the head of the list.
         */
@@ -1946,7 +1946,7 @@ static int diAllocExt(struct inomap * imap, int agno, struct inode *ip)
        } else {
                /* read the iag.
                 */
-               IREAD_LOCK(imap->im_ipimap);
+               IREAD_LOCK(imap->im_ipimap, RDWRLOCK_IMAP);
                if ((rc = diIAGRead(imap, iagno, &mp))) {
                        IREAD_UNLOCK(imap->im_ipimap);
                        jfs_error(ip->i_sb, "diAllocExt: error reading iag");
@@ -2509,7 +2509,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
                 */
 
                /* acquire inode map lock */
-               IWRITE_LOCK(ipimap);
+               IWRITE_LOCK(ipimap, RDWRLOCK_IMAP);
 
                if (ipimap->i_size >> L2PSIZE != imap->im_nextiag + 1) {
                        IWRITE_UNLOCK(ipimap);
@@ -2648,7 +2648,7 @@ diNewIAG(struct inomap * imap, int *iagnop, int agno, struct metapage ** mpp)
        }
 
        /* obtain read lock on map */
-       IREAD_LOCK(ipimap);
+       IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
 
        /* read the iag */
        if ((rc = diIAGRead(imap, iagno, &mp))) {
@@ -2779,7 +2779,7 @@ diUpdatePMap(struct inode *ipimap,
                return -EIO;
        }
        /* read the iag */
-       IREAD_LOCK(ipimap);
+       IREAD_LOCK(ipimap, RDWRLOCK_IMAP);
        rc = diIAGRead(imap, iagno, &mp);
        IREAD_UNLOCK(ipimap);
        if (rc)
index 9400558..8f453ef 100644 (file)
@@ -109,9 +109,11 @@ struct jfs_inode_info {
 
 #define JFS_ACL_NOT_CACHED ((void *)-1)
 
-#define IREAD_LOCK(ip)         down_read(&JFS_IP(ip)->rdwrlock)
+#define IREAD_LOCK(ip, subclass) \
+       down_read_nested(&JFS_IP(ip)->rdwrlock, subclass)
 #define IREAD_UNLOCK(ip)       up_read(&JFS_IP(ip)->rdwrlock)
-#define IWRITE_LOCK(ip)                down_write(&JFS_IP(ip)->rdwrlock)
+#define IWRITE_LOCK(ip, subclass) \
+       down_write_nested(&JFS_IP(ip)->rdwrlock, subclass)
 #define IWRITE_UNLOCK(ip)      up_write(&JFS_IP(ip)->rdwrlock)
 
 /*
@@ -127,6 +129,29 @@ enum cflags {
        COMMIT_Synclist,        /* metadata pages on group commit synclist */
 };
 
+/*
+ * commit_mutex nesting subclasses:
+ */
+enum commit_mutex_class
+{
+       COMMIT_MUTEX_PARENT,
+       COMMIT_MUTEX_CHILD,
+       COMMIT_MUTEX_SECOND_PARENT,     /* Renaming */
+       COMMIT_MUTEX_VICTIM             /* Inode being unlinked due to rename */
+};
+
+/*
+ * rdwrlock subclasses:
+ * The dmap inode may be locked while a normal inode or the imap inode are
+ * locked.
+ */
+enum rdwrlock_class
+{
+       RDWRLOCK_NORMAL,
+       RDWRLOCK_IMAP,
+       RDWRLOCK_DMAP
+};
+
 #define set_cflag(flag, ip)    set_bit(flag, &(JFS_IP(ip)->cflag))
 #define clear_cflag(flag, ip)  clear_bit(flag, &(JFS_IP(ip)->cflag))
 #define test_cflag(flag, ip)   test_bit(flag, &(JFS_IP(ip)->cflag))
index 7d78e83..df48ece 100644 (file)
@@ -42,7 +42,7 @@ do {                                                  \
                if (cond)                               \
                        break;                          \
                unlock_cmd;                             \
-               schedule();                             \
+               io_schedule();                          \
                lock_cmd;                               \
        }                                               \
        current->state = TASK_RUNNING;                  \
index ceaf03b..58deae0 100644 (file)
@@ -56,7 +56,7 @@ static inline void __lock_metapage(struct metapage *mp)
                set_current_state(TASK_UNINTERRUPTIBLE);
                if (metapage_locked(mp)) {
                        unlock_page(mp->page);
-                       schedule();
+                       io_schedule();
                        lock_page(mp->page);
                }
        } while (trylock_metapage(mp));
index d558e51..6988a10 100644 (file)
@@ -135,7 +135,7 @@ static inline void TXN_SLEEP_DROP_LOCK(wait_queue_head_t * event)
        add_wait_queue(event, &wait);
        set_current_state(TASK_UNINTERRUPTIBLE);
        TXN_UNLOCK();
-       schedule();
+       io_schedule();
        current->state = TASK_RUNNING;
        remove_wait_queue(event, &wait);
 }
index e98eb03..acc97c4 100644 (file)
@@ -757,6 +757,11 @@ static int xtSearch(struct inode *ip, s64 xoff,    s64 *nextp,
                        nsplit = 0;
 
                /* push (bn, index) of the parent page/entry */
+               if (BT_STACK_FULL(btstack)) {
+                       jfs_error(ip->i_sb, "stack overrun in xtSearch!");
+                       XT_PUTPAGE(mp);
+                       return -EIO;
+               }
                BT_PUSH(btstack, bn, index);
 
                /* get the child page block number */
@@ -3915,6 +3920,11 @@ s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
         */
       getChild:
        /* save current parent entry for the child page */
+       if (BT_STACK_FULL(&btstack)) {
+               jfs_error(ip->i_sb, "stack overrun in xtTruncate!");
+               XT_PUTPAGE(mp);
+               return -EIO;
+       }
        BT_PUSH(&btstack, bn, index);
 
        /* get child page */
@@ -4112,6 +4122,11 @@ s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
         */
       getChild:
        /* save current parent entry for the child page */
+       if (BT_STACK_FULL(&btstack)) {
+               jfs_error(ip->i_sb, "stack overrun in xtTruncate_pmap!");
+               XT_PUTPAGE(mp);
+               return -EIO;
+       }
        BT_PUSH(&btstack, bn, index);
 
        /* get child page */
index a6a8c16..7ab4756 100644 (file)
@@ -104,8 +104,8 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, int mode,
 
        tid = txBegin(dip->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dip)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        rc = jfs_init_acl(tid, ip, dip);
        if (rc)
@@ -238,8 +238,8 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, int mode)
 
        tid = txBegin(dip->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dip)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        rc = jfs_init_acl(tid, ip, dip);
        if (rc)
@@ -365,8 +365,8 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
 
        tid = txBegin(dip->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dip)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        iplist[0] = dip;
        iplist[1] = ip;
@@ -483,12 +483,12 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
        if ((rc = get_UCSname(&dname, dentry)))
                goto out;
 
-       IWRITE_LOCK(ip);
+       IWRITE_LOCK(ip, RDWRLOCK_NORMAL);
 
        tid = txBegin(dip->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dip)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        iplist[0] = dip;
        iplist[1] = ip;
@@ -802,8 +802,8 @@ static int jfs_link(struct dentry *old_dentry,
 
        tid = txBegin(ip->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dir)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        /*
         * scan parent directory for entry/freespace
@@ -913,8 +913,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
 
        tid = txBegin(dip->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dip)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dip)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        rc = jfs_init_security(tid, ip, dip);
        if (rc)
@@ -1127,7 +1127,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                        goto out3;
                }
        } else if (new_ip) {
-               IWRITE_LOCK(new_ip);
+               IWRITE_LOCK(new_ip, RDWRLOCK_NORMAL);
                /* Init inode for quota operations. */
                DQUOT_INIT(new_ip);
        }
@@ -1137,13 +1137,21 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
         */
        tid = txBegin(new_dir->i_sb, 0);
 
-       mutex_lock(&JFS_IP(new_dir)->commit_mutex);
-       mutex_lock(&JFS_IP(old_ip)->commit_mutex);
+       /*
+        * How do we know the locking is safe from deadlocks?
+        * The vfs does the hard part for us.  Any time we are taking nested
+        * commit_mutexes, the vfs already has i_mutex held on the parent.
+        * Here, the vfs has already taken i_mutex on both old_dir and new_dir.
+        */
+       mutex_lock_nested(&JFS_IP(new_dir)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(old_ip)->commit_mutex, COMMIT_MUTEX_CHILD);
        if (old_dir != new_dir)
-               mutex_lock(&JFS_IP(old_dir)->commit_mutex);
+               mutex_lock_nested(&JFS_IP(old_dir)->commit_mutex,
+                                 COMMIT_MUTEX_SECOND_PARENT);
 
        if (new_ip) {
-               mutex_lock(&JFS_IP(new_ip)->commit_mutex);
+               mutex_lock_nested(&JFS_IP(new_ip)->commit_mutex,
+                                 COMMIT_MUTEX_VICTIM);
                /*
                 * Change existing directory entry to new inode number
                 */
@@ -1357,8 +1365,8 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
 
        tid = txBegin(dir->i_sb, 0);
 
-       mutex_lock(&JFS_IP(dir)->commit_mutex);
-       mutex_lock(&JFS_IP(ip)->commit_mutex);
+       mutex_lock_nested(&JFS_IP(dir)->commit_mutex, COMMIT_MUTEX_PARENT);
+       mutex_lock_nested(&JFS_IP(ip)->commit_mutex, COMMIT_MUTEX_CHILD);
 
        rc = jfs_init_acl(tid, ip, dir);
        if (rc)
index e121636..d026b4f 100644 (file)
@@ -306,8 +306,8 @@ int                  ocfs2_journal_dirty_data(handle_t *handle,
  * for the dinode, one for the new block. */
 #define OCFS2_SIMPLE_DIR_EXTEND_CREDITS (2)
 
-/* file update (nlink, etc) + dir entry block */
-#define OCFS2_LINK_CREDITS  (OCFS2_INODE_UPDATE_CREDITS + 1)
+/* file update (nlink, etc) + directory mtime/ctime + dir entry block */
+#define OCFS2_LINK_CREDITS  (2*OCFS2_INODE_UPDATE_CREDITS + 1)
 
 /* inode + dir inode (if we unlink a dir), + dir entry block + orphan
  * dir inode link */
index e8f540d..d3b9f5f 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 
 #include <asm/uaccess.h>
+#include <asm/semaphore.h>
 
 #include "sysfs.h"
 
@@ -146,7 +147,7 @@ static int open(struct inode * inode, struct file * file)
  Error:
        module_put(attr->attr.owner);
  Done:
-       if (error && kobj)
+       if (error)
                kobject_put(kobj);
        return error;
 }
@@ -157,8 +158,7 @@ static int release(struct inode * inode, struct file * file)
        struct bin_attribute * attr = to_bin_attr(file->f_path.dentry);
        u8 * buffer = file->private_data;
 
-       if (kobj) 
-               kobject_put(kobj);
+       kobject_put(kobj);
        module_put(attr->attr.owner);
        kfree(buffer);
        return 0;
index 511edef..9dcdf55 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/module.h>
 #include <linux/kobject.h>
 #include <linux/namei.h>
+#include <asm/semaphore.h>
 #include "sysfs.h"
 
 DECLARE_RWSEM(sysfs_rename_sem);
@@ -32,8 +33,7 @@ static struct dentry_operations sysfs_dentry_ops = {
 /*
  * Allocates a new sysfs_dirent and links it to the parent sysfs_dirent
  */
-static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
-                                               void * element)
+static struct sysfs_dirent * __sysfs_new_dirent(void * element)
 {
        struct sysfs_dirent * sd;
 
@@ -45,12 +45,28 @@ static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent * parent_sd,
        atomic_set(&sd->s_count, 1);
        atomic_set(&sd->s_event, 1);
        INIT_LIST_HEAD(&sd->s_children);
-       list_add(&sd->s_sibling, &parent_sd->s_children);
+       INIT_LIST_HEAD(&sd->s_sibling);
        sd->s_element = element;
 
        return sd;
 }
 
+static void __sysfs_list_dirent(struct sysfs_dirent *parent_sd,
+                             struct sysfs_dirent *sd)
+{
+       if (sd)
+               list_add(&sd->s_sibling, &parent_sd->s_children);
+}
+
+static struct sysfs_dirent * sysfs_new_dirent(struct sysfs_dirent *parent_sd,
+                                               void * element)
+{
+       struct sysfs_dirent *sd;
+       sd = __sysfs_new_dirent(element);
+       __sysfs_list_dirent(parent_sd, sd);
+       return sd;
+}
+
 /*
  *
  * Return -EEXIST if there is already a sysfs element with the same name for
@@ -77,14 +93,14 @@ int sysfs_dirent_exist(struct sysfs_dirent *parent_sd,
 }
 
 
-int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
-                       void * element, umode_t mode, int type)
+static struct sysfs_dirent *
+__sysfs_make_dirent(struct dentry *dentry, void *element, mode_t mode, int type)
 {
        struct sysfs_dirent * sd;
 
-       sd = sysfs_new_dirent(parent_sd, element);
+       sd = __sysfs_new_dirent(element);
        if (!sd)
-               return -ENOMEM;
+               goto out;
 
        sd->s_mode = mode;
        sd->s_type = type;
@@ -94,7 +110,19 @@ int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
                dentry->d_op = &sysfs_dentry_ops;
        }
 
-       return 0;
+out:
+       return sd;
+}
+
+int sysfs_make_dirent(struct sysfs_dirent * parent_sd, struct dentry * dentry,
+                       void * element, umode_t mode, int type)
+{
+       struct sysfs_dirent *sd;
+
+       sd = __sysfs_make_dirent(dentry, element, mode, type);
+       __sysfs_list_dirent(parent_sd, sd);
+
+       return sd ? 0 : -ENOMEM;
 }
 
 static int init_dir(struct inode * inode)
@@ -165,11 +193,11 @@ int sysfs_create_subdir(struct kobject * k, const char * n, struct dentry ** d)
 
 /**
  *     sysfs_create_dir - create a directory for an object.
- *     @parent:        parent parent object.
  *     @kobj:          object we're creating directory for. 
+ *     @shadow_parent: parent parent object.
  */
 
-int sysfs_create_dir(struct kobject * kobj)
+int sysfs_create_dir(struct kobject * kobj, struct dentry *shadow_parent)
 {
        struct dentry * dentry = NULL;
        struct dentry * parent;
@@ -177,7 +205,9 @@ int sysfs_create_dir(struct kobject * kobj)
 
        BUG_ON(!kobj);
 
-       if (kobj->parent)
+       if (shadow_parent)
+               parent = shadow_parent;
+       else if (kobj->parent)
                parent = kobj->parent->dentry;
        else if (sysfs_mount && sysfs_mount->mnt_sb)
                parent = sysfs_mount->mnt_sb->s_root;
@@ -298,21 +328,12 @@ void sysfs_remove_subdir(struct dentry * d)
 }
 
 
-/**
- *     sysfs_remove_dir - remove an object's directory.
- *     @kobj:  object. 
- *
- *     The only thing special about this is that we remove any files in 
- *     the directory before we remove the directory, and we've inlined
- *     what used to be sysfs_rmdir() below, instead of calling separately.
- */
-
-void sysfs_remove_dir(struct kobject * kobj)
+static void __sysfs_remove_dir(struct dentry *dentry)
 {
-       struct dentry * dentry = dget(kobj->dentry);
        struct sysfs_dirent * parent_sd;
        struct sysfs_dirent * sd, * tmp;
 
+       dget(dentry);
        if (!dentry)
                return;
 
@@ -333,32 +354,60 @@ void sysfs_remove_dir(struct kobject * kobj)
         * Drop reference from dget() on entrance.
         */
        dput(dentry);
+}
+
+/**
+ *     sysfs_remove_dir - remove an object's directory.
+ *     @kobj:  object.
+ *
+ *     The only thing special about this is that we remove any files in
+ *     the directory before we remove the directory, and we've inlined
+ *     what used to be sysfs_rmdir() below, instead of calling separately.
+ */
+
+void sysfs_remove_dir(struct kobject * kobj)
+{
+       __sysfs_remove_dir(kobj->dentry);
        kobj->dentry = NULL;
 }
 
-int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
+int sysfs_rename_dir(struct kobject * kobj, struct dentry *new_parent,
+                    const char *new_name)
 {
        int error = 0;
-       struct dentry * new_dentry, * parent;
-
-       if (!strcmp(kobject_name(kobj), new_name))
-               return -EINVAL;
+       struct dentry * new_dentry;
 
-       if (!kobj->parent)
-               return -EINVAL;
+       if (!new_parent)
+               return -EFAULT;
 
        down_write(&sysfs_rename_sem);
-       parent = kobj->parent->dentry;
-
-       mutex_lock(&parent->d_inode->i_mutex);
+       mutex_lock(&new_parent->d_inode->i_mutex);
 
-       new_dentry = lookup_one_len(new_name, parent, strlen(new_name));
+       new_dentry = lookup_one_len(new_name, new_parent, strlen(new_name));
        if (!IS_ERR(new_dentry)) {
-               if (!new_dentry->d_inode) {
+               /* By allowing two different directories with the
+                * same d_parent we allow this routine to move
+                * between different shadows of the same directory
+                */
+               if (kobj->dentry->d_parent->d_inode != new_parent->d_inode)
+                       return -EINVAL;
+               else if (new_dentry->d_parent->d_inode != new_parent->d_inode)
+                       error = -EINVAL;
+               else if (new_dentry == kobj->dentry)
+                       error = -EINVAL;
+               else if (!new_dentry->d_inode) {
                        error = kobject_set_name(kobj, "%s", new_name);
                        if (!error) {
+                               struct sysfs_dirent *sd, *parent_sd;
+
                                d_add(new_dentry, NULL);
                                d_move(kobj->dentry, new_dentry);
+
+                               sd = kobj->dentry->d_fsdata;
+                               parent_sd = new_parent->d_fsdata;
+
+                               list_del_init(&sd->s_sibling);
+                               list_add(&sd->s_sibling, &parent_sd->s_children);
                        }
                        else
                                d_drop(new_dentry);
@@ -366,7 +415,7 @@ int sysfs_rename_dir(struct kobject * kobj, const char *new_name)
                        error = -EEXIST;
                dput(new_dentry);
        }
-       mutex_unlock(&parent->d_inode->i_mutex);
+       mutex_unlock(&new_parent->d_inode->i_mutex);
        up_write(&sysfs_rename_sem);
 
        return error;
@@ -378,12 +427,10 @@ int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent)
        struct sysfs_dirent *new_parent_sd, *sd;
        int error;
 
-       if (!new_parent)
-               return -EINVAL;
-
        old_parent_dentry = kobj->parent ?
                kobj->parent->dentry : sysfs_mount->mnt_sb->s_root;
-       new_parent_dentry = new_parent->dentry;
+       new_parent_dentry = new_parent ?
+               new_parent->dentry : sysfs_mount->mnt_sb->s_root;
 
 again:
        mutex_lock(&old_parent_dentry->d_inode->i_mutex);
@@ -547,6 +594,95 @@ static loff_t sysfs_dir_lseek(struct file * file, loff_t offset, int origin)
        return offset;
 }
 
+
+/**
+ *     sysfs_make_shadowed_dir - Setup so a directory can be shadowed
+ *     @kobj:  object we're creating shadow of.
+ */
+
+int sysfs_make_shadowed_dir(struct kobject *kobj,
+       void * (*follow_link)(struct dentry *, struct nameidata *))
+{
+       struct inode *inode;
+       struct inode_operations *i_op;
+
+       inode = kobj->dentry->d_inode;
+       if (inode->i_op != &sysfs_dir_inode_operations)
+               return -EINVAL;
+
+       i_op = kmalloc(sizeof(*i_op), GFP_KERNEL);
+       if (!i_op)
+               return -ENOMEM;
+
+       memcpy(i_op, &sysfs_dir_inode_operations, sizeof(*i_op));
+       i_op->follow_link = follow_link;
+
+       /* Locking of inode->i_op?
+        * Since setting i_op is a single word write and they
+        * are atomic we should be ok here.
+        */
+       inode->i_op = i_op;
+       return 0;
+}
+
+/**
+ *     sysfs_create_shadow_dir - create a shadow directory for an object.
+ *     @kobj:  object we're creating directory for.
+ *
+ *     sysfs_make_shadowed_dir must already have been called on this
+ *     directory.
+ */
+
+struct dentry *sysfs_create_shadow_dir(struct kobject *kobj)
+{
+       struct sysfs_dirent *sd;
+       struct dentry *parent, *dir, *shadow;
+       struct inode *inode;
+
+       dir = kobj->dentry;
+       inode = dir->d_inode;
+       parent = dir->d_parent;
+       shadow = ERR_PTR(-EINVAL);
+       if (!sysfs_is_shadowed_inode(inode))
+               goto out;
+
+       shadow = d_alloc(parent, &dir->d_name);
+       if (!shadow)
+               goto nomem;
+
+       sd = __sysfs_make_dirent(shadow, kobj, inode->i_mode, SYSFS_DIR);
+       if (!sd)
+               goto nomem;
+
+       d_instantiate(shadow, igrab(inode));
+       inc_nlink(inode);
+       inc_nlink(parent->d_inode);
+       shadow->d_op = &sysfs_dentry_ops;
+
+       dget(shadow);           /* Extra count - pin the dentry in core */
+
+out:
+       return shadow;
+nomem:
+       dput(shadow);
+       shadow = ERR_PTR(-ENOMEM);
+       goto out;
+}
+
+/**
+ *     sysfs_remove_shadow_dir - remove an object's directory.
+ *     @shadow: dentry of shadow directory
+ *
+ *     The only thing special about this is that we remove any files in
+ *     the directory before we remove the directory, and we've inlined
+ *     what used to be sysfs_rmdir() below, instead of calling separately.
+ */
+
+void sysfs_remove_shadow_dir(struct dentry *shadow)
+{
+       __sysfs_remove_dir(shadow);
+}
+
 const struct file_operations sysfs_dir_operations = {
        .open           = sysfs_dir_open,
        .release        = sysfs_dir_close,
index 9cfe53e..c0e1176 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/kobject.h>
 #include <linux/namei.h>
 #include <linux/poll.h>
+#include <linux/list.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
 
@@ -50,17 +51,29 @@ static struct sysfs_ops subsys_sysfs_ops = {
        .store  = subsys_attr_store,
 };
 
+/**
+ *     add_to_collection - add buffer to a collection
+ *     @buffer:        buffer to be added
+ *     @node           inode of set to add to
+ */
 
-struct sysfs_buffer {
-       size_t                  count;
-       loff_t                  pos;
-       char                    * page;
-       struct sysfs_ops        * ops;
-       struct semaphore        sem;
-       int                     needs_read_fill;
-       int                     event;
-};
+static inline void
+add_to_collection(struct sysfs_buffer *buffer, struct inode *node)
+{
+       struct sysfs_buffer_collection *set = node->i_private;
 
+       mutex_lock(&node->i_mutex);
+       list_add(&buffer->associates, &set->associates);
+       mutex_unlock(&node->i_mutex);
+}
+
+static inline void
+remove_from_collection(struct sysfs_buffer *buffer, struct inode *node)
+{
+       mutex_lock(&node->i_mutex);
+       list_del(&buffer->associates);
+       mutex_unlock(&node->i_mutex);
+}
 
 /**
  *     fill_read_buffer - allocate and fill buffer from object.
@@ -70,7 +83,8 @@ struct sysfs_buffer {
  *     Allocate @buffer->page, if it hasn't been already, then call the
  *     kobject's show() method to fill the buffer with this attribute's 
  *     data. 
- *     This is called only once, on the file's first read. 
+ *     This is called only once, on the file's first read unless an error
+ *     is returned.
  */
 static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer)
 {
@@ -88,12 +102,13 @@ static int fill_read_buffer(struct dentry * dentry, struct sysfs_buffer * buffer
 
        buffer->event = atomic_read(&sd->s_event);
        count = ops->show(kobj,attr,buffer->page);
-       buffer->needs_read_fill = 0;
        BUG_ON(count > (ssize_t)PAGE_SIZE);
-       if (count >= 0)
+       if (count >= 0) {
+               buffer->needs_read_fill = 0;
                buffer->count = count;
-       else
+       } else {
                ret = count;
+       }
        return ret;
 }
 
@@ -153,6 +168,10 @@ sysfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        ssize_t retval = 0;
 
        down(&buffer->sem);
+       if (buffer->orphaned) {
+               retval = -ENODEV;
+               goto out;
+       }
        if (buffer->needs_read_fill) {
                if ((retval = fill_read_buffer(file->f_path.dentry,buffer)))
                        goto out;
@@ -165,7 +184,6 @@ out:
        return retval;
 }
 
-
 /**
  *     fill_write_buffer - copy buffer from userspace.
  *     @buffer:        data buffer for file.
@@ -243,19 +261,25 @@ sysfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t
        ssize_t len;
 
        down(&buffer->sem);
+       if (buffer->orphaned) {
+               len = -ENODEV;
+               goto out;
+       }
        len = fill_write_buffer(buffer, buf, count);
        if (len > 0)
                len = flush_write_buffer(file->f_path.dentry, buffer, len);
        if (len > 0)
                *ppos += len;
+out:
        up(&buffer->sem);
        return len;
 }
 
-static int check_perm(struct inode * inode, struct file * file)
+static int sysfs_open_file(struct inode *inode, struct file *file)
 {
        struct kobject *kobj = sysfs_get_kobject(file->f_path.dentry->d_parent);
        struct attribute * attr = to_attr(file->f_path.dentry);
+       struct sysfs_buffer_collection *set;
        struct sysfs_buffer * buffer;
        struct sysfs_ops * ops = NULL;
        int error = 0;
@@ -285,6 +309,18 @@ static int check_perm(struct inode * inode, struct file * file)
        if (!ops)
                goto Eaccess;
 
+       /* make sure we have a collection to add our buffers to */
+       mutex_lock(&inode->i_mutex);
+       if (!(set = inode->i_private)) {
+               if (!(set = inode->i_private = kmalloc(sizeof(struct sysfs_buffer_collection), GFP_KERNEL))) {
+                       error = -ENOMEM;
+                       goto Done;
+               } else {
+                       INIT_LIST_HEAD(&set->associates);
+               }
+       }
+       mutex_unlock(&inode->i_mutex);
+
        /* File needs write support.
         * The inode's perms must say it's ok, 
         * and we must have a store method.
@@ -310,9 +346,11 @@ static int check_perm(struct inode * inode, struct file * file)
         */
        buffer = kzalloc(sizeof(struct sysfs_buffer), GFP_KERNEL);
        if (buffer) {
+               INIT_LIST_HEAD(&buffer->associates);
                init_MUTEX(&buffer->sem);
                buffer->needs_read_fill = 1;
                buffer->ops = ops;
+               add_to_collection(buffer, inode);
                file->private_data = buffer;
        } else
                error = -ENOMEM;
@@ -325,16 +363,11 @@ static int check_perm(struct inode * inode, struct file * file)
        error = -EACCES;
        module_put(attr->owner);
  Done:
-       if (error && kobj)
+       if (error)
                kobject_put(kobj);
        return error;
 }
 
-static int sysfs_open_file(struct inode * inode, struct file * filp)
-{
-       return check_perm(inode,filp);
-}
-
 static int sysfs_release(struct inode * inode, struct file * filp)
 {
        struct kobject * kobj = to_kobj(filp->f_path.dentry->d_parent);
@@ -342,8 +375,9 @@ static int sysfs_release(struct inode * inode, struct file * filp)
        struct module * owner = attr->owner;
        struct sysfs_buffer * buffer = filp->private_data;
 
-       if (kobj) 
-               kobject_put(kobj);
+       if (buffer)
+               remove_from_collection(buffer, inode);
+       kobject_put(kobj);
        /* After this point, attr should not be accessed. */
        module_put(owner);
 
@@ -548,7 +582,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file);
 
 void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
 {
-       sysfs_hash_and_remove(kobj->dentry,attr->name);
+       sysfs_hash_and_remove(kobj->dentry, attr->name);
 }
 
 
index 122145b..b20951c 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/dcache.h>
 #include <linux/namei.h>
 #include <linux/err.h>
+#include <linux/fs.h>
+#include <asm/semaphore.h>
 #include "sysfs.h"
 
 
index e79e38d..542d2bc 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/backing-dev.h>
 #include <linux/capability.h>
 #include <linux/errno.h>
+#include <asm/semaphore.h>
 #include "sysfs.h"
 
 extern struct super_block * sysfs_sb;
@@ -32,6 +33,16 @@ static struct inode_operations sysfs_inode_operations ={
        .setattr        = sysfs_setattr,
 };
 
+void sysfs_delete_inode(struct inode *inode)
+{
+       /* Free the shadowed directory inode operations */
+       if (sysfs_is_shadowed_inode(inode)) {
+               kfree(inode->i_op);
+               inode->i_op = NULL;
+       }
+       return generic_delete_inode(inode);
+}
+
 int sysfs_setattr(struct dentry * dentry, struct iattr * iattr)
 {
        struct inode * inode = dentry->d_inode;
@@ -209,6 +220,22 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
        return NULL;
 }
 
+static inline void orphan_all_buffers(struct inode *node)
+{
+       struct sysfs_buffer_collection *set = node->i_private;
+       struct sysfs_buffer *buf;
+
+       mutex_lock_nested(&node->i_mutex, I_MUTEX_CHILD);
+       if (node->i_private) {
+               list_for_each_entry(buf, &set->associates, associates) {
+                       down(&buf->sem);
+                       buf->orphaned = 1;
+                       up(&buf->sem);
+               }
+       }
+       mutex_unlock(&node->i_mutex);
+}
+
 
 /*
  * Unhashes the dentry corresponding to given sysfs_dirent
@@ -217,16 +244,23 @@ const unsigned char * sysfs_get_name(struct sysfs_dirent *sd)
 void sysfs_drop_dentry(struct sysfs_dirent * sd, struct dentry * parent)
 {
        struct dentry * dentry = sd->s_dentry;
+       struct inode *inode;
 
        if (dentry) {
                spin_lock(&dcache_lock);
                spin_lock(&dentry->d_lock);
                if (!(d_unhashed(dentry) && dentry->d_inode)) {
+                       inode = dentry->d_inode;
+                       spin_lock(&inode->i_lock);
+                       __iget(inode);
+                       spin_unlock(&inode->i_lock);
                        dget_locked(dentry);
                        __d_drop(dentry);
                        spin_unlock(&dentry->d_lock);
                        spin_unlock(&dcache_lock);
                        simple_unlink(parent->d_inode, dentry);
+                       orphan_all_buffers(inode);
+                       iput(inode);
                } else {
                        spin_unlock(&dentry->d_lock);
                        spin_unlock(&dcache_lock);
@@ -248,7 +282,7 @@ int sysfs_hash_and_remove(struct dentry * dir, const char * name)
                return -ENOENT;
 
        parent_sd = dir->d_fsdata;
-       mutex_lock(&dir->d_inode->i_mutex);
+       mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
        list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
                if (!sd->s_element)
                        continue;
index e503f85..f6a87a8 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/mount.h>
 #include <linux/pagemap.h>
 #include <linux/init.h>
+#include <asm/semaphore.h>
 
 #include "sysfs.h"
 
@@ -18,9 +19,12 @@ struct vfsmount *sysfs_mount;
 struct super_block * sysfs_sb = NULL;
 struct kmem_cache *sysfs_dir_cachep;
 
+static void sysfs_clear_inode(struct inode *inode);
+
 static struct super_operations sysfs_ops = {
        .statfs         = simple_statfs,
-       .drop_inode     = generic_delete_inode,
+       .drop_inode     = sysfs_delete_inode,
+       .clear_inode    = sysfs_clear_inode,
 };
 
 static struct sysfs_dirent sysfs_root = {
@@ -31,6 +35,11 @@ static struct sysfs_dirent sysfs_root = {
        .s_iattr        = NULL,
 };
 
+static void sysfs_clear_inode(struct inode *inode)
+{
+       kfree(inode->i_private);
+}
+
 static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct inode *inode;
index f50e3cc..4869f61 100644 (file)
@@ -7,6 +7,7 @@
 #include <linux/module.h>
 #include <linux/kobject.h>
 #include <linux/namei.h>
+#include <asm/semaphore.h>
 
 #include "sysfs.h"
 
index bd7cec2..fe1cbfd 100644 (file)
@@ -2,6 +2,7 @@
 extern struct vfsmount * sysfs_mount;
 extern struct kmem_cache *sysfs_dir_cachep;
 
+extern void sysfs_delete_inode(struct inode *inode);
 extern struct inode * sysfs_new_inode(mode_t mode, struct sysfs_dirent *);
 extern int sysfs_create(struct dentry *, int mode, int (*init)(struct inode *));
 
@@ -33,6 +34,22 @@ struct sysfs_symlink {
        struct kobject * target_kobj;
 };
 
+struct sysfs_buffer {
+       struct list_head                associates;
+       size_t                          count;
+       loff_t                          pos;
+       char                            * page;
+       struct sysfs_ops                * ops;
+       struct semaphore                sem;
+       int                             orphaned;
+       int                             needs_read_fill;
+       int                             event;
+};
+
+struct sysfs_buffer_collection {
+       struct list_head        associates;
+};
+
 static inline struct kobject * to_kobj(struct dentry * dentry)
 {
        struct sysfs_dirent * sd = dentry->d_fsdata;
@@ -96,3 +113,7 @@ static inline void sysfs_put(struct sysfs_dirent * sd)
                release_sysfs_dirent(sd);
 }
 
+static inline int sysfs_is_shadowed_inode(struct inode *inode)
+{
+       return S_ISDIR(inode->i_mode) && inode->i_op->follow_link;
+}
index ebc1f69..422f29c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -63,7 +63,7 @@
 
 /* Current ACPICA subsystem version in YYYYMMDD format */
 
-#define ACPI_CA_VERSION                 0x20060707
+#define ACPI_CA_VERSION                 0x20070126
 
 /*
  * OS name, used for the _OS object.  The _OS object is essentially obsolete,
 
 #define ACPI_NUM_OWNERID_MASKS          8
 
+/* Size of the root table array is increased by this increment */
+
+#define ACPI_ROOT_TABLE_SIZE_INCREMENT  4
+
 /******************************************************************************
  *
  * ACPI Specification constants (Do not change unless the specification changes)
 #define ACPI_PATH_SEGMENT_LENGTH        5      /* 4 chars for name + 1 char for separator */
 #define ACPI_PATH_SEPARATOR             '.'
 
+/* Sizes for ACPI table headers */
+
+#define ACPI_OEM_ID_SIZE                6
+#define ACPI_OEM_TABLE_ID_SIZE          8
+
 /* Constants used in searching for the RSDP in low memory */
 
 #define ACPI_EBDA_PTR_LOCATION          0x0000040E     /* Physical Address */
index d816709..d626bb1 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -159,6 +159,10 @@ void
 acpi_db_create_execution_threads(char *num_threads_arg,
                                 char *num_loops_arg, char *method_name_arg);
 
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+u32 acpi_db_get_cache_info(struct acpi_memory_list *cache);
+#endif
+
 /*
  * dbfileio - Debugger file I/O commands
  */
@@ -214,4 +218,6 @@ void acpi_db_prep_namestring(char *name);
 
 struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name);
 
+void acpi_db_uint32_to_hex_string(u32 value, char *buffer);
+
 #endif                         /* __ACDEBUG_H__ */
index 9a7d692..389d772 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -97,9 +97,11 @@ typedef const struct acpi_dmtable_info {
 #define ACPI_DMT_CHKSUM                 20
 #define ACPI_DMT_SPACEID                21
 #define ACPI_DMT_GAS                    22
-#define ACPI_DMT_MADT                   23
-#define ACPI_DMT_SRAT                   24
-#define ACPI_DMT_EXIT                   25
+#define ACPI_DMT_DMAR                   23
+#define ACPI_DMT_MADT                   24
+#define ACPI_DMT_SRAT                   25
+#define ACPI_DMT_EXIT                   26
+#define ACPI_DMT_SIG                    27
 
 typedef
 void (*ACPI_TABLE_HANDLER) (struct acpi_table_header * table);
@@ -108,6 +110,7 @@ struct acpi_dmtable_data {
        char *signature;
        struct acpi_dmtable_info *table_info;
        ACPI_TABLE_HANDLER table_handler;
+       char *name;
 };
 
 struct acpi_op_walk_info {
@@ -139,7 +142,9 @@ extern const char *acpi_gbl_match_ops[];
 
 extern struct acpi_dmtable_info acpi_dm_table_info_asf0[];
 extern struct acpi_dmtable_info acpi_dm_table_info_asf1[];
+extern struct acpi_dmtable_info acpi_dm_table_info_asf1a[];
 extern struct acpi_dmtable_info acpi_dm_table_info_asf2[];
+extern struct acpi_dmtable_info acpi_dm_table_info_asf2a[];
 extern struct acpi_dmtable_info acpi_dm_table_info_asf3[];
 extern struct acpi_dmtable_info acpi_dm_table_info_asf4[];
 extern struct acpi_dmtable_info acpi_dm_table_info_asf_hdr[];
@@ -147,6 +152,11 @@ extern struct acpi_dmtable_info acpi_dm_table_info_boot[];
 extern struct acpi_dmtable_info acpi_dm_table_info_cpep[];
 extern struct acpi_dmtable_info acpi_dm_table_info_cpep0[];
 extern struct acpi_dmtable_info acpi_dm_table_info_dbgp[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar_hdr[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar_scope[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar0[];
+extern struct acpi_dmtable_info acpi_dm_table_info_dmar1[];
 extern struct acpi_dmtable_info acpi_dm_table_info_ecdt[];
 extern struct acpi_dmtable_info acpi_dm_table_info_facs[];
 extern struct acpi_dmtable_info acpi_dm_table_info_fadt1[];
@@ -201,6 +211,8 @@ void acpi_dm_dump_asf(struct acpi_table_header *table);
 
 void acpi_dm_dump_cpep(struct acpi_table_header *table);
 
+void acpi_dm_dump_dmar(struct acpi_table_header *table);
+
 void acpi_dm_dump_fadt(struct acpi_table_header *table);
 
 void acpi_dm_dump_srat(struct acpi_table_header *table);
@@ -314,7 +326,7 @@ acpi_dm_resource_template(struct acpi_op_walk_info *info,
                          union acpi_parse_object *op,
                          u8 * byte_data, u32 byte_count);
 
-u8 acpi_dm_is_resource_template(union acpi_parse_object *op);
+acpi_status acpi_dm_is_resource_template(union acpi_parse_object *op);
 
 void acpi_dm_indent(u32 level);
 
index a22fe9c..cb8d286 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -210,7 +210,7 @@ acpi_ds_method_error(acpi_status status, struct acpi_walk_state *walk_state);
  * dsinit
  */
 acpi_status
-acpi_ds_initialize_objects(struct acpi_table_desc *table_desc,
+acpi_ds_initialize_objects(acpi_native_uint table_index,
                           struct acpi_namespace_node *start_node);
 
 /*
index 2341428..d23cdf3 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 797ca1e..b73f18a 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define AE_CTRL_BREAK                   (acpi_status) (0x0009 | AE_CODE_CONTROL)
 #define AE_CTRL_CONTINUE                (acpi_status) (0x000A | AE_CODE_CONTROL)
 #define AE_CTRL_SKIP                    (acpi_status) (0x000B | AE_CODE_CONTROL)
+#define AE_CTRL_PARSE_CONTINUE          (acpi_status) (0x000C | AE_CODE_CONTROL)
+#define AE_CTRL_PARSE_PENDING           (acpi_status) (0x000D | AE_CODE_CONTROL)
 
-#define AE_CODE_CTRL_MAX                0x000B
+#define AE_CODE_CTRL_MAX                0x000D
 
 #ifdef DEFINE_ACPI_GLOBALS
 
@@ -291,7 +293,9 @@ char const *acpi_gbl_exception_names_ctrl[] = {
        "AE_CTRL_TRANSFER",
        "AE_CTRL_BREAK",
        "AE_CTRL_CONTINUE",
-       "AE_CTRL_SKIP"
+       "AE_CTRL_SKIP",
+       "AE_CTRL_PARSE_CONTINUE",
+       "AE_CTRL_PARSE_PENDING"
 };
 
 #endif                         /* ACPI GLOBALS */
index 06972e6..24c3f05 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define ACPI_INIT_GLOBAL(a,b) a
 #endif
 
-/*
- * Keep local copies of these FADT-based registers.  NOTE: These globals
- * are first in this file for alignment reasons on 64-bit systems.
- */
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
-ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
-
-/*****************************************************************************
- *
- * Debug support
- *
- ****************************************************************************/
-
-/* Runtime configuration of debug print levels */
-
-extern u32 acpi_dbg_level;
-extern u32 acpi_dbg_layer;
-
-/* Procedure nesting level for debug output */
-
-extern u32 acpi_gbl_nesting_level;
-
-/* Support for dynamic control method tracing mechanism */
-
-ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
-ACPI_EXTERN u32 acpi_gbl_original_dbg_layer;
-ACPI_EXTERN acpi_name acpi_gbl_trace_method_name;
-ACPI_EXTERN u32 acpi_gbl_trace_dbg_level;
-ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
-ACPI_EXTERN u32 acpi_gbl_trace_flags;
-
 /*****************************************************************************
  *
  * Runtime configuration (static defaults that can be overriden at runtime)
@@ -133,6 +102,34 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_create_osi_method, TRUE);
  */
 ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE);
 
+/*****************************************************************************
+ *
+ * Debug support
+ *
+ ****************************************************************************/
+
+/* Runtime configuration of debug print levels */
+
+extern u32 acpi_dbg_level;
+extern u32 acpi_dbg_layer;
+
+/* Procedure nesting level for debug output */
+
+extern u32 acpi_gbl_nesting_level;
+
+/* Event counters */
+
+ACPI_EXTERN u32 acpi_gpe_count;
+
+/* Support for dynamic control method tracing mechanism */
+
+ACPI_EXTERN u32 acpi_gbl_original_dbg_level;
+ACPI_EXTERN u32 acpi_gbl_original_dbg_layer;
+ACPI_EXTERN acpi_name acpi_gbl_trace_method_name;
+ACPI_EXTERN u32 acpi_gbl_trace_dbg_level;
+ACPI_EXTERN u32 acpi_gbl_trace_dbg_layer;
+ACPI_EXTERN u32 acpi_gbl_trace_flags;
+
 /*****************************************************************************
  *
  * ACPI Table globals
@@ -140,47 +137,29 @@ ACPI_EXTERN u8 ACPI_INIT_GLOBAL(acpi_gbl_leave_wake_gpes_disabled, TRUE);
  ****************************************************************************/
 
 /*
- * Table pointers.
- * Although these pointers are somewhat redundant with the global acpi_table,
- * they are convenient because they are typed pointers.
+ * acpi_gbl_root_table_list is the master list of ACPI tables found in the
+ * RSDT/XSDT.
  *
- * These tables are single-table only; meaning that there can be at most one
- * of each in the system.  Each global points to the actual table.
- */
-ACPI_EXTERN u32 acpi_gbl_table_flags;
-ACPI_EXTERN u32 acpi_gbl_rsdt_table_count;
-ACPI_EXTERN struct rsdp_descriptor *acpi_gbl_RSDP;
-ACPI_EXTERN struct xsdt_descriptor *acpi_gbl_XSDT;
-ACPI_EXTERN struct fadt_descriptor *acpi_gbl_FADT;
-ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT;
-ACPI_EXTERN struct facs_descriptor *acpi_gbl_FACS;
-ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS;
-/*
- * Since there may be multiple SSDTs and PSDTs, a single pointer is not
- * sufficient; Therefore, there isn't one!
+ * acpi_gbl_FADT is a local copy of the FADT, converted to a common format.
  */
+ACPI_EXTERN struct acpi_internal_rsdt acpi_gbl_root_table_list;
+ACPI_EXTERN struct acpi_table_fadt acpi_gbl_FADT;
+extern acpi_native_uint acpi_gbl_permanent_mmap;
 
-/* The root table can be either an RSDT or an XSDT */
+/* These addresses are calculated from FADT address values */
 
-ACPI_EXTERN u8 acpi_gbl_root_table_type;
-#define     ACPI_TABLE_TYPE_RSDT        'R'
-#define     ACPI_TABLE_TYPE_XSDT        'X'
+ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1a_enable;
+ACPI_EXTERN struct acpi_generic_address acpi_gbl_xpm1b_enable;
 
 /*
- * Handle both ACPI 1.0 and ACPI 2.0 Integer widths:
- * If we are executing a method that exists in a 32-bit ACPI table,
- * use only the lower 32 bits of the (internal) 64-bit Integer.
+ * Handle both ACPI 1.0 and ACPI 2.0 Integer widths. The integer width is
+ * determined by the revision of the DSDT: If the DSDT revision is less than
+ * 2, use only the lower 32 bits of the internal 64-bit Integer.
  */
 ACPI_EXTERN u8 acpi_gbl_integer_bit_width;
 ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
 ACPI_EXTERN u8 acpi_gbl_integer_nybble_width;
 
-/*
- * ACPI Table info arrays
- */
-extern struct acpi_table_list acpi_gbl_table_lists[ACPI_TABLE_ID_MAX + 1];
-extern struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1];
-
 /*****************************************************************************
  *
  * Mutual exlusion within ACPICA subsystem
@@ -188,7 +167,7 @@ extern struct acpi_table_support acpi_gbl_table_data[ACPI_TABLE_ID_MAX + 1];
  ****************************************************************************/
 
 /*
- * Predefined mutex objects.  This array contains the
+ * Predefined mutex objects. This array contains the
  * actual OS mutex handles, indexed by the local ACPI_MUTEX_HANDLEs.
  * (The table maps local handles to the real OS handles)
  */
@@ -197,6 +176,7 @@ ACPI_EXTERN struct acpi_mutex_info acpi_gbl_mutex_info[ACPI_NUM_MUTEX];
 /*
  * Global lock semaphore works in conjunction with the actual HW global lock
  */
+ACPI_EXTERN acpi_mutex acpi_gbl_global_lock_mutex;
 ACPI_EXTERN acpi_semaphore acpi_gbl_global_lock_semaphore;
 
 /*
@@ -220,6 +200,7 @@ ACPI_EXTERN spinlock_t _acpi_gbl_hardware_lock;     /* For ACPI H/W except GPE regis
 
 ACPI_EXTERN struct acpi_memory_list *acpi_gbl_global_list;
 ACPI_EXTERN struct acpi_memory_list *acpi_gbl_ns_node_list;
+ACPI_EXTERN u8 acpi_gbl_display_final_mem_stats;
 #endif
 
 /* Object caches */
@@ -240,7 +221,6 @@ ACPI_EXTERN struct acpi_walk_state *acpi_gbl_breakpoint_walk;
 
 /* Misc */
 
-ACPI_EXTERN u32 acpi_gbl_global_lock_thread_count;
 ACPI_EXTERN u32 acpi_gbl_original_mode;
 ACPI_EXTERN u32 acpi_gbl_rsdp_original_location;
 ACPI_EXTERN u32 acpi_gbl_ns_lookup_count;
@@ -260,12 +240,19 @@ ACPI_EXTERN u8 acpi_gbl_system_awake_and_running;
 
 extern u8 acpi_gbl_shutdown;
 extern u32 acpi_gbl_startup_flags;
-extern const u8 acpi_gbl_decode_to8bit[8];
 extern const char *acpi_gbl_sleep_state_names[ACPI_S_STATE_COUNT];
 extern const char *acpi_gbl_highest_dstate_names[4];
 extern const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES];
 extern const char *acpi_gbl_region_types[ACPI_NUM_PREDEFINED_REGIONS];
 
+/* Exception codes */
+
+extern char const *acpi_gbl_exception_names_env[];
+extern char const *acpi_gbl_exception_names_pgm[];
+extern char const *acpi_gbl_exception_names_tbl[];
+extern char const *acpi_gbl_exception_names_aml[];
+extern char const *acpi_gbl_exception_names_ctrl[];
+
 /*****************************************************************************
  *
  * Namespace globals
index 29b60a8..9df275c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -61,8 +61,6 @@
 /*
  * hwacpi - high level functions
  */
-acpi_status acpi_hw_initialize(void);
-
 acpi_status acpi_hw_set_mode(u32 mode);
 
 u32 acpi_hw_get_mode(void);
@@ -84,7 +82,7 @@ acpi_hw_low_level_read(u32 width,
 acpi_status
 acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address *reg);
 
-acpi_status acpi_hw_clear_acpi_status(u32 flags);
+acpi_status acpi_hw_clear_acpi_status(void);
 
 /*
  * hwgpe - GPE support
index 91586d0..ce7c9d6 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -277,12 +277,6 @@ acpi_status acpi_ex_system_do_suspend(acpi_integer time);
 
 acpi_status acpi_ex_system_do_stall(u32 time);
 
-acpi_status
-acpi_ex_system_acquire_mutex(union acpi_operand_object *time,
-                            union acpi_operand_object *obj_desc);
-
-acpi_status acpi_ex_system_release_mutex(union acpi_operand_object *obj_desc);
-
 acpi_status acpi_ex_system_signal_event(union acpi_operand_object *obj_desc);
 
 acpi_status
@@ -451,10 +445,14 @@ acpi_ex_copy_integer_to_buffer_field(union acpi_operand_object *source_desc,
 /*
  * exutils - interpreter/scanner utilities
  */
-acpi_status acpi_ex_enter_interpreter(void);
+void acpi_ex_enter_interpreter(void);
 
 void acpi_ex_exit_interpreter(void);
 
+void acpi_ex_reacquire_interpreter(void);
+
+void acpi_ex_relinquish_interpreter(void);
+
 void acpi_ex_truncate_for32bit_table(union acpi_operand_object *obj_desc);
 
 u8 acpi_ex_acquire_global_lock(u32 rule);
index 063c4b5..6f83ddb 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -80,8 +80,8 @@ union acpi_parse_object;
  * table below also!
  */
 #define ACPI_MTX_INTERPRETER            0      /* AML Interpreter, main lock */
-#define ACPI_MTX_TABLES                 1      /* Data for ACPI tables */
-#define ACPI_MTX_NAMESPACE              2      /* ACPI Namespace */
+#define ACPI_MTX_NAMESPACE              1      /* ACPI Namespace */
+#define ACPI_MTX_TABLES                 2      /* Data for ACPI tables */
 #define ACPI_MTX_EVENTS                 3      /* Data for ACPI events */
 #define ACPI_MTX_CACHES                 4      /* Internal caches, general purposes */
 #define ACPI_MTX_MEMORY                 5      /* Debug memory tracking lists */
@@ -162,7 +162,7 @@ struct acpi_mutex_info {
 typedef enum {
        ACPI_IMODE_LOAD_PASS1 = 0x01,
        ACPI_IMODE_LOAD_PASS2 = 0x02,
-       ACPI_IMODE_EXECUTE = 0x0E
+       ACPI_IMODE_EXECUTE = 0x03
 } acpi_interpreter_mode;
 
 union acpi_name_union {
@@ -204,7 +204,7 @@ struct acpi_namespace_node {
 /* Namespace Node flags */
 
 #define ANOBJ_END_OF_PEER_LIST          0x01   /* End-of-list, Peer field points to parent */
-#define ANOBJ_RESERVED                  0x02   /* Available for future use */
+#define ANOBJ_TEMPORARY                 0x02   /* Node is create by a method and is temporary */
 #define ANOBJ_METHOD_ARG                0x04   /* Node is a method argument */
 #define ANOBJ_METHOD_LOCAL              0x08   /* Node is a method local */
 #define ANOBJ_SUBTREE_HAS_INI           0x10   /* Used to optimize device initialization */
@@ -219,25 +219,42 @@ struct acpi_namespace_node {
  * ACPI Table Descriptor.  One per ACPI table
  */
 struct acpi_table_desc {
-       struct acpi_table_desc *prev;
-       struct acpi_table_desc *next;
-       struct acpi_table_desc *installed_desc;
+       acpi_physical_address address;
        struct acpi_table_header *pointer;
-       u8 *aml_start;
-       u64 physical_address;
-       acpi_size length;
-       u32 aml_length;
+       u32 length;             /* Length fixed at 32 bits */
+       union acpi_name_union signature;
        acpi_owner_id owner_id;
-       u8 type;
-       u8 allocation;
-       u8 loaded_into_namespace;
+       u8 flags;
 };
 
-struct acpi_table_list {
-       struct acpi_table_desc *next;
+/* Flags for above */
+
+#define ACPI_TABLE_ORIGIN_UNKNOWN       (0)
+#define ACPI_TABLE_ORIGIN_MAPPED        (1)
+#define ACPI_TABLE_ORIGIN_ALLOCATED     (2)
+#define ACPI_TABLE_ORIGIN_MASK          (3)
+#define ACPI_TABLE_IS_LOADED            (4)
+
+/* One internal RSDT for table management */
+
+struct acpi_internal_rsdt {
+       struct acpi_table_desc *tables;
        u32 count;
+       u32 size;
+       u8 flags;
 };
 
+/* Flags for above */
+
+#define ACPI_ROOT_ORIGIN_UNKNOWN        (0)    /* ~ORIGIN_ALLOCATED */
+#define ACPI_ROOT_ORIGIN_ALLOCATED      (1)
+#define ACPI_ROOT_ALLOW_RESIZE          (2)
+
+/* Predefined (fixed) table indexes */
+
+#define ACPI_TABLE_INDEX_DSDT           (0)
+#define ACPI_TABLE_INDEX_FACS           (1)
+
 struct acpi_find_context {
        char *search_for;
        acpi_handle *list;
@@ -350,7 +367,7 @@ struct acpi_gpe_event_info {
        union acpi_gpe_dispatch_info dispatch;  /* Either Method or Handler */
        struct acpi_gpe_register_info *register_info;   /* Backpointer to register info */
        u8 flags;               /* Misc info about this GPE */
-       u8 register_bit;        /* This GPE bit within the register */
+       u8 gpe_number;          /* This GPE */
 };
 
 /* Information about a GPE register pair, one per each status/enable pair in an array */
@@ -855,12 +872,30 @@ struct acpi_bit_register_info {
  ****************************************************************************/
 
 struct acpi_db_method_info {
-       acpi_handle thread_gate;
+       acpi_handle main_thread_gate;
+       acpi_handle thread_complete_gate;
+       u32 *threads;
+       u32 num_threads;
+       u32 num_created;
+       u32 num_completed;
+
        char *name;
-       char **args;
        u32 flags;
        u32 num_loops;
        char pathname[128];
+       char **args;
+
+       /*
+        * Arguments to be passed to method for the command
+        * Threads -
+        *   the Number of threads, ID of current thread and
+        *   Index of current thread inside all them created.
+        */
+       char init_args;
+       char *arguments[4];
+       char num_threads_str[11];
+       char id_of_thread_str[11];
+       char index_of_thread_str[11];
 };
 
 struct acpi_integrity_info {
@@ -919,6 +954,8 @@ struct acpi_memory_list {
 
        u32 total_allocated;
        u32 total_freed;
+       u32 max_occupied;
+       u32 total_size;
        u32 current_total_size;
        u32 requests;
        u32 hits;
index 192fa09..8948a64 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define ACPI_SET_BIT(target,bit)        ((target) |= (bit))
 #define ACPI_CLEAR_BIT(target,bit)      ((target) &= ~(bit))
 #define ACPI_MIN(a,b)                   (((a)<(b))?(a):(b))
+#define ACPI_MAX(a,b)                   (((a)>(b))?(a):(b))
 
 /* Size calculation */
 
 #define ACPI_ARRAY_LENGTH(x)            (sizeof(x) / sizeof((x)[0]))
 
-#if ACPI_MACHINE_WIDTH == 16
-
-/*
- * For 16-bit addresses, we have to assume that the upper 32 bits
- * (out of 64) are zero.
- */
-#define ACPI_LODWORD(l)                 ((u32)(l))
-#define ACPI_HIDWORD(l)                 ((u32)(0))
-
-#define ACPI_GET_ADDRESS(a)             ((a).lo)
-#define ACPI_STORE_ADDRESS(a,b)         {(a).hi=0;(a).lo=(u32)(b);}
-#define ACPI_VALID_ADDRESS(a)           ((a).hi | (a).lo)
-
-#else
 #ifdef ACPI_NO_INTEGER64_SUPPORT
 /*
  * acpi_integer is 32-bits, no 64-bit support on this platform
 #define ACPI_LODWORD(l)                 ((u32)(l))
 #define ACPI_HIDWORD(l)                 ((u32)(0))
 
-#define ACPI_GET_ADDRESS(a)             (a)
-#define ACPI_STORE_ADDRESS(a,b)         ((a)=(b))
-#define ACPI_VALID_ADDRESS(a)           (a)
-
 #else
 
 /*
  */
 #define ACPI_LODWORD(l)                 ((u32)(u64)(l))
 #define ACPI_HIDWORD(l)                 ((u32)(((*(struct uint64_struct *)(void *)(&l))).hi))
-
-#define ACPI_GET_ADDRESS(a)             (a)
-#define ACPI_STORE_ADDRESS(a,b)         ((a)=(acpi_physical_address)(b))
-#define ACPI_VALID_ADDRESS(a)           (a)
-#endif
 #endif
 
 /*
 #define ACPI_TO_POINTER(i)              ACPI_ADD_PTR (void,(void *) NULL,(acpi_native_uint) i)
 #define ACPI_TO_INTEGER(p)              ACPI_PTR_DIFF (p,(void *) NULL)
 #define ACPI_OFFSET(d,f)                (acpi_size) ACPI_PTR_DIFF (&(((d *)0)->f),(void *) NULL)
-
-#if ACPI_MACHINE_WIDTH == 16
-#define ACPI_STORE_POINTER(d,s)         ACPI_MOVE_32_TO_32(d,s)
-#define ACPI_PHYSADDR_TO_PTR(i)         (void *)(i)
-#define ACPI_PTR_TO_PHYSADDR(i)         (u32) ACPI_CAST_PTR (u8,(i))
-#else
 #define ACPI_PHYSADDR_TO_PTR(i)         ACPI_TO_POINTER(i)
 #define ACPI_PTR_TO_PHYSADDR(i)         ACPI_TO_INTEGER(i)
-#endif
 
 #ifndef ACPI_MISALIGNMENT_NOT_SUPPORTED
 #define ACPI_COMPARE_NAME(a,b)          (*ACPI_CAST_PTR (u32,(a)) == *ACPI_CAST_PTR (u32,(b)))
 
 /* The hardware supports unaligned transfers, just do the little-endian move */
 
-#if ACPI_MACHINE_WIDTH == 16
-
-/* No 64-bit integers */
-/* 16-bit source, 16/32/64 destination */
-
-#define ACPI_MOVE_16_TO_16(d,s)         *(u16 *)(void *)(d) = *(u16 *)(void *)(s)
-#define ACPI_MOVE_16_TO_32(d,s)         *(u32 *)(void *)(d) = *(u16 *)(void *)(s)
-#define ACPI_MOVE_16_TO_64(d,s)         ACPI_MOVE_16_TO_32(d,s)
-
-/* 32-bit source, 16/32/64 destination */
-
-#define ACPI_MOVE_32_TO_16(d,s)         ACPI_MOVE_16_TO_16(d,s)        /* Truncate to 16 */
-#define ACPI_MOVE_32_TO_32(d,s)         *(u32 *)(void *)(d) = *(u32 *)(void *)(s)
-#define ACPI_MOVE_32_TO_64(d,s)         ACPI_MOVE_32_TO_32(d,s)
-
-/* 64-bit source, 16/32/64 destination */
-
-#define ACPI_MOVE_64_TO_16(d,s)         ACPI_MOVE_16_TO_16(d,s)        /* Truncate to 16 */
-#define ACPI_MOVE_64_TO_32(d,s)         ACPI_MOVE_32_TO_32(d,s)        /* Truncate to 32 */
-#define ACPI_MOVE_64_TO_64(d,s)         ACPI_MOVE_32_TO_32(d,s)
-
-#else
 /* 16-bit source, 16/32/64 destination */
 
 #define ACPI_MOVE_16_TO_16(d,s)         *(u16 *)(void *)(d) = *(u16 *)(void *)(s)
 #define ACPI_MOVE_64_TO_16(d,s)         ACPI_MOVE_16_TO_16(d,s)        /* Truncate to 16 */
 #define ACPI_MOVE_64_TO_32(d,s)         ACPI_MOVE_32_TO_32(d,s)        /* Truncate to 32 */
 #define ACPI_MOVE_64_TO_64(d,s)         *(u64 *)(void *)(d) = *(u64 *)(void *)(s)
-#endif
 
 #else
 /*
 
 /* Macros based on machine integer width */
 
-#if ACPI_MACHINE_WIDTH == 16
-#define ACPI_MOVE_SIZE_TO_16(d,s)       ACPI_MOVE_16_TO_16(d,s)
-
-#elif ACPI_MACHINE_WIDTH == 32
+#if ACPI_MACHINE_WIDTH == 32
 #define ACPI_MOVE_SIZE_TO_16(d,s)       ACPI_MOVE_32_TO_16(d,s)
 
 #elif ACPI_MACHINE_WIDTH == 64
 #define ACPI_DEBUGGER_EXEC(a)
 #endif
 
-/*
- * For 16-bit code, we want to shrink some things even though
- * we are using ACPI_DEBUG_OUTPUT to get the debug output
- */
-#if ACPI_MACHINE_WIDTH == 16
-#undef ACPI_DEBUG_ONLY_MEMBERS
-#undef _VERBOSE_STRUCTURES
-#define ACPI_DEBUG_ONLY_MEMBERS(a)
-#endif
-
 #ifdef ACPI_DEBUG_OUTPUT
 /*
  * 1) Set name to blanks
index b67da36..34bfae8 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 83b52f9..535b7e1 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define ACPI_NS_ERROR_IF_FOUND      0x08
 #define ACPI_NS_PREFIX_IS_SCOPE     0x10
 #define ACPI_NS_EXTERNAL            0x20
+#define ACPI_NS_TEMPORARY           0x40
 
-#define ACPI_NS_WALK_UNLOCK         TRUE
-#define ACPI_NS_WALK_NO_UNLOCK      FALSE
+/* Flags for acpi_ns_walk_namespace */
+
+#define ACPI_NS_WALK_NO_UNLOCK      0
+#define ACPI_NS_WALK_UNLOCK         0x01
+#define ACPI_NS_WALK_TEMP_NODES     0x02
 
 /*
  * nsinit - Namespace initialization
@@ -82,7 +86,7 @@ acpi_status acpi_ns_initialize_devices(void);
 acpi_status acpi_ns_load_namespace(void);
 
 acpi_status
-acpi_ns_load_table(struct acpi_table_desc *table_desc,
+acpi_ns_load_table(acpi_native_uint table_index,
                   struct acpi_namespace_node *node);
 
 /*
@@ -92,7 +96,7 @@ acpi_status
 acpi_ns_walk_namespace(acpi_object_type type,
                       acpi_handle start_object,
                       u32 max_depth,
-                      u8 unlock_before_callback,
+                      u32 flags,
                       acpi_walk_callback user_function,
                       void *context, void **return_value);
 
@@ -106,11 +110,12 @@ struct acpi_namespace_node *acpi_ns_get_next_node(acpi_object_type type,
  * nsparse - table parsing
  */
 acpi_status
-acpi_ns_parse_table(struct acpi_table_desc *table_desc,
-                   struct acpi_namespace_node *scope);
+acpi_ns_parse_table(acpi_native_uint table_index,
+                   struct acpi_namespace_node *start_node);
 
 acpi_status
-acpi_ns_one_complete_parse(u8 pass_number, struct acpi_table_desc *table_desc);
+acpi_ns_one_complete_parse(acpi_native_uint pass_number,
+                          acpi_native_uint table_index);
 
 /*
  * nsaccess - Top-level namespace access
index 8fdee31..04e9735 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * to the interpreter, and to keep track of the various handlers such as
  * address space handlers and notify handlers. The object is a constant
  * size in order to allow it to be cached and reused.
+ *
+ * Note: The object is optimized to be aligned and will not work if it is
+ * byte-packed.
  */
+#if ACPI_MACHINE_WIDTH == 64
+#pragma pack(8)
+#else
+#pragma pack(4)
+#endif
 
 /*******************************************************************************
  *
@@ -101,7 +109,8 @@ struct acpi_object_common {
 ACPI_OBJECT_COMMON_HEADER};
 
 struct acpi_object_integer {
-       ACPI_OBJECT_COMMON_HEADER acpi_integer value;
+       ACPI_OBJECT_COMMON_HEADER u8 fill[3];   /* Prevent warning on some compilers */
+       acpi_integer value;
 };
 
 /*
@@ -203,7 +212,9 @@ struct acpi_object_power_resource {
 };
 
 struct acpi_object_processor {
-       ACPI_OBJECT_COMMON_HEADER u8 proc_id;
+       ACPI_OBJECT_COMMON_HEADER
+           /* The next two fields take advantage of the 3-byte space before NOTIFY_INFO */
+       u8 proc_id;
        u8 length;
         ACPI_COMMON_NOTIFY_INFO acpi_io_address address;
 };
@@ -406,4 +417,6 @@ union acpi_descriptor {
        union acpi_parse_object op;
 };
 
+#pragma pack()
+
 #endif                         /* _ACOBJECT_H */
index 7659a46..e6f76a2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define ARGI_LLESSEQUAL_OP              ARGI_INVALID_OPCODE
 #define ARGI_LNOT_OP                    ARGI_LIST1 (ARGI_INTEGER)
 #define ARGI_LNOTEQUAL_OP               ARGI_INVALID_OPCODE
-#define ARGI_LOAD_OP                    ARGI_LIST2 (ARGI_REGION_OR_FIELD,ARGI_TARGETREF)
+#define ARGI_LOAD_OP                    ARGI_LIST2 (ARGI_REGION_OR_BUFFER,ARGI_TARGETREF)
 #define ARGI_LOAD_TABLE_OP              ARGI_LIST6 (ARGI_STRING,     ARGI_STRING,        ARGI_STRING,       ARGI_STRING,    ARGI_STRING, ARGI_ANYTYPE)
 #define ARGI_LOCAL0                     ARG_NONE
 #define ARGI_LOCAL1                     ARG_NONE
index 8d5039d..7812267 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 9d49d3c..85c358e 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b9a39d1..2e5f00d 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index fdd1095..0d9f984 100644 (file)
@@ -59,7 +59,6 @@ acpi_evaluate_reference(acpi_handle handle,
 
 #define ACPI_BUS_FILE_ROOT     "acpi"
 extern struct proc_dir_entry *acpi_root_dir;
-extern struct fadt_descriptor acpi_fadt;
 
 enum acpi_bus_removal_type {
        ACPI_BUS_REMOVAL_NORMAL = 0,
@@ -92,13 +91,12 @@ typedef int (*acpi_op_remove) (struct acpi_device * device, int type);
 typedef int (*acpi_op_lock) (struct acpi_device * device, int type);
 typedef int (*acpi_op_start) (struct acpi_device * device);
 typedef int (*acpi_op_stop) (struct acpi_device * device, int type);
-typedef int (*acpi_op_suspend) (struct acpi_device * device, int state);
-typedef int (*acpi_op_resume) (struct acpi_device * device, int state);
+typedef int (*acpi_op_suspend) (struct acpi_device * device, pm_message_t state);
+typedef int (*acpi_op_resume) (struct acpi_device * device);
 typedef int (*acpi_op_scan) (struct acpi_device * device);
 typedef int (*acpi_op_bind) (struct acpi_device * device);
 typedef int (*acpi_op_unbind) (struct acpi_device * device);
-typedef int (*acpi_op_match) (struct acpi_device * device,
-                             struct acpi_driver * driver);
+typedef int (*acpi_op_shutdown) (struct acpi_device * device);
 
 struct acpi_bus_ops {
        u32 acpi_op_add:1;
@@ -111,7 +109,7 @@ struct acpi_bus_ops {
        u32 acpi_op_scan:1;
        u32 acpi_op_bind:1;
        u32 acpi_op_unbind:1;
-       u32 acpi_op_match:1;
+       u32 acpi_op_shutdown:1;
        u32 reserved:21;
 };
 
@@ -126,16 +124,16 @@ struct acpi_device_ops {
        acpi_op_scan scan;
        acpi_op_bind bind;
        acpi_op_unbind unbind;
-       acpi_op_match match;
+       acpi_op_shutdown shutdown;
 };
 
 struct acpi_driver {
-       struct list_head node;
        char name[80];
        char class[80];
-       atomic_t references;
        char *ids;              /* Supported Hardware IDs */
        struct acpi_device_ops ops;
+       struct device_driver drv;
+       struct module *owner;
 };
 
 /*
@@ -185,7 +183,7 @@ struct acpi_device_dir {
 
 typedef char acpi_bus_id[5];
 typedef unsigned long acpi_bus_address;
-typedef char acpi_hardware_id[9];
+typedef char acpi_hardware_id[15];
 typedef char acpi_unique_id[9];
 typedef char acpi_device_name[40];
 typedef char acpi_device_class[20];
@@ -296,11 +294,14 @@ struct acpi_device {
        struct acpi_device_ops ops;
        struct acpi_driver *driver;
        void *driver_data;
-       struct kobject kobj;
        struct device dev;
+       struct acpi_bus_ops bus_ops;    /* workaround for different code path for hotplug */
+       enum acpi_bus_removal_type removal_type; /* indicate for different removal type */
 };
 
 #define acpi_driver_data(d)    ((d)->driver_data)
+#define to_acpi_device(d)      container_of(d, struct acpi_device, dev)
+#define to_acpi_driver(d)      container_of(d, struct acpi_driver, drv)
 
 /*
  * Events
index 6a5bdce..4dc8a50 100644 (file)
 
 /* _HID definitions */
 
-#define ACPI_POWER_HID                 "ACPI_PWR"
-#define ACPI_PROCESSOR_HID             "ACPI_CPU"
-#define ACPI_SYSTEM_HID                        "ACPI_SYS"
-#define ACPI_THERMAL_HID               "ACPI_THM"
-#define ACPI_BUTTON_HID_POWERF         "ACPI_FPB"
-#define ACPI_BUTTON_HID_SLEEPF         "ACPI_FSB"
-
+#define ACPI_POWER_HID                 "power_resource"
+#define ACPI_PROCESSOR_HID             "ACPI0007"
+#define ACPI_SYSTEM_HID                        "acpi_system"
+#define ACPI_THERMAL_HID               "thermal"
+#define ACPI_BUTTON_HID_POWERF         "button_power"
+#define ACPI_BUTTON_HID_SLEEPF         "button_sleep"
+#define ACPI_VIDEO_HID                 "video"
+#define ACPI_BAY_HID                   "bay"
 /* --------------------------------------------------------------------------
                                        PCI
    -------------------------------------------------------------------------- */
index 0cd63bc..781394b 100644 (file)
@@ -8,7 +8,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -85,7 +85,7 @@ acpi_status acpi_os_terminate(void);
 /*
  * ACPI Table interfaces
  */
-acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *address);
+acpi_physical_address acpi_os_get_root_pointer(void);
 
 acpi_status
 acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
@@ -143,9 +143,7 @@ void acpi_os_release_mutex(acpi_mutex handle);
  */
 void *acpi_os_allocate(acpi_size size);
 
-acpi_status
-acpi_os_map_memory(acpi_physical_address physical_address,
-                  acpi_size size, void __iomem ** logical_address);
+void __iomem *acpi_os_map_memory(acpi_physical_address where, acpi_native_uint length);
 
 void acpi_os_unmap_memory(void __iomem * logical_address, acpi_size size);
 
index 8145876..e08f7df 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 /*
  * Global interfaces
  */
+acpi_status
+acpi_initialize_tables(struct acpi_table_desc *initial_storage,
+                      u32 initial_table_count, u8 allow_resize);
+
 acpi_status acpi_initialize_subsystem(void);
 
 acpi_status acpi_enable_subsystem(u32 flags);
@@ -92,30 +96,28 @@ void acpi_free(void *address);
 /*
  * ACPI table manipulation interfaces
  */
-acpi_status
-acpi_find_root_pointer(u32 flags, struct acpi_pointer *rsdp_address);
+acpi_status acpi_reallocate_root_table(void);
+
+acpi_status acpi_find_root_pointer(acpi_native_uint * rsdp_address);
 
 acpi_status acpi_load_tables(void);
 
 acpi_status acpi_load_table(struct acpi_table_header *table_ptr);
 
-acpi_status acpi_unload_table_id(acpi_table_type table_type, acpi_owner_id id);
+acpi_status acpi_unload_table_id(acpi_owner_id id);
 
-#ifdef ACPI_FUTURE_USAGE
-acpi_status acpi_unload_table(acpi_table_type table_type);
 acpi_status
-acpi_get_table_header(acpi_table_type table_type,
-                     u32 instance, struct acpi_table_header *out_table_header);
-#endif                         /*  ACPI_FUTURE_USAGE  */
+acpi_get_table_header(acpi_string signature,
+                     acpi_native_uint instance,
+                     struct acpi_table_header *out_table_header);
 
 acpi_status
-acpi_get_table(acpi_table_type table_type,
-              u32 instance, struct acpi_buffer *ret_buffer);
+acpi_get_table(acpi_string signature,
+              acpi_native_uint instance, struct acpi_table_header **out_table);
 
 acpi_status
-acpi_get_firmware_table(acpi_string signature,
-                       u32 instance,
-                       u32 flags, struct acpi_table_header **table_pointer);
+acpi_get_table_by_index(acpi_native_uint table_index,
+                       struct acpi_table_header **out_table);
 
 /*
  * Namespace and name interfaces
@@ -310,9 +312,9 @@ acpi_resource_to_address64(struct acpi_resource *resource,
 /*
  * Hardware (ACPI device) interfaces
  */
-acpi_status acpi_get_register(u32 register_id, u32 * return_value, u32 flags);
+acpi_status acpi_get_register(u32 register_id, u32 * return_value);
 
-acpi_status acpi_set_register(u32 register_id, u32 value, u32 flags);
+acpi_status acpi_set_register(u32 register_id, u32 value);
 
 acpi_status
 acpi_set_firmware_waking_vector(acpi_physical_address physical_address);
index 80a3b33..9486ab2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 5e8095f..aeb4498 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -139,7 +139,8 @@ struct acpi_init_walk_info {
        u16 buffer_init;
        u16 package_init;
        u16 object_count;
-       struct acpi_table_desc *table_desc;
+       acpi_owner_id owner_id;
+       acpi_native_uint table_index;
 };
 
 struct acpi_get_devices_info {
index 4dbaf02..2b9f46f 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #ifndef __ACTABLES_H__
 #define __ACTABLES_H__
 
-/* Used in acpi_tb_map_acpi_table for size parameter if table header is to be used */
-
-#define SIZE_IN_HEADER          0
+acpi_status acpi_allocate_root_table(u32 initial_table_count);
 
 /*
- * tbconvrt - Table conversion routines
+ * tbfadt - FADT parse/convert/validate
  */
-acpi_status acpi_tb_convert_to_xsdt(struct acpi_table_desc *table_info);
-
-acpi_status acpi_tb_convert_table_fadt(void);
+void acpi_tb_parse_fadt(acpi_native_uint table_index, u8 flags);
 
-acpi_status acpi_tb_build_common_facs(struct acpi_table_desc *table_info);
-
-u32
-acpi_tb_get_table_count(struct rsdp_descriptor *RSDP,
-                       struct acpi_table_header *RSDT);
+void acpi_tb_create_local_fadt(struct acpi_table_header *table, u32 length);
 
 /*
- * tbget - Table "get" routines
+ * tbfind - find ACPI table
  */
 acpi_status
-acpi_tb_get_table(struct acpi_pointer *address,
-                 struct acpi_table_desc *table_info);
-
-acpi_status
-acpi_tb_get_table_header(struct acpi_pointer *address,
-                        struct acpi_table_header *return_header);
-
-acpi_status
-acpi_tb_get_table_body(struct acpi_pointer *address,
-                      struct acpi_table_header *header,
-                      struct acpi_table_desc *table_info);
-
-acpi_status
-acpi_tb_get_table_ptr(acpi_table_type table_type,
-                     u32 instance, struct acpi_table_header **table_ptr_loc);
-
-acpi_status acpi_tb_verify_rsdp(struct acpi_pointer *address);
-
-void acpi_tb_get_rsdt_address(struct acpi_pointer *out_address);
-
-acpi_status acpi_tb_validate_rsdt(struct acpi_table_header *table_ptr);
+acpi_tb_find_table(char *signature,
+                  char *oem_id,
+                  char *oem_table_id, acpi_native_uint * table_index);
 
 /*
- * tbgetall - get multiple required tables
+ * tbinstal - Table removal and deletion
  */
-acpi_status acpi_tb_get_required_tables(void);
+acpi_status acpi_tb_resize_root_table_list(void);
 
-/*
- * tbinstall - Table installation
- */
-acpi_status acpi_tb_install_table(struct acpi_table_desc *table_info);
+acpi_status acpi_tb_verify_table(struct acpi_table_desc *table_desc);
 
 acpi_status
-acpi_tb_recognize_table(struct acpi_table_desc *table_info, u8 search_type);
+acpi_tb_add_table(struct acpi_table_desc *table_desc,
+                 acpi_native_uint * table_index);
 
 acpi_status
-acpi_tb_init_table_descriptor(acpi_table_type table_type,
-                             struct acpi_table_desc *table_info);
+acpi_tb_store_table(acpi_physical_address address,
+                   struct acpi_table_header *table,
+                   u32 length, u8 flags, acpi_native_uint * table_index);
 
-/*
- * tbremove - Table removal and deletion
- */
-void acpi_tb_delete_all_tables(void);
+void acpi_tb_delete_table(struct acpi_table_desc *table_desc);
 
-void acpi_tb_delete_tables_by_type(acpi_table_type type);
+void acpi_tb_terminate(void);
 
-void acpi_tb_delete_single_table(struct acpi_table_desc *table_desc);
+void acpi_tb_delete_namespace_by_owner(acpi_native_uint table_index);
 
-struct acpi_table_desc *acpi_tb_uninstall_table(struct acpi_table_desc
-                                               *table_desc);
+acpi_status acpi_tb_allocate_owner_id(acpi_native_uint table_index);
+
+acpi_status acpi_tb_release_owner_id(acpi_native_uint table_index);
 
-/*
- * tbxfroot - RSDP, RSDT utilities
- */
 acpi_status
-acpi_tb_find_table(char *signature,
-                  char *oem_id,
-                  char *oem_table_id, struct acpi_table_header **table_ptr);
+acpi_tb_get_owner_id(acpi_native_uint table_index, acpi_owner_id * owner_id);
 
-acpi_status acpi_tb_get_table_rsdt(void);
+u8 acpi_tb_is_table_loaded(acpi_native_uint table_index);
 
-acpi_status acpi_tb_validate_rsdp(struct rsdp_descriptor *rsdp);
+void acpi_tb_set_table_loaded_flag(acpi_native_uint table_index, u8 is_loaded);
 
 /*
- * tbutils - common table utilities
+ * tbutils - table manager utilities
  */
-acpi_status acpi_tb_is_table_installed(struct acpi_table_desc *new_table_desc);
+u8 acpi_tb_tables_loaded(void);
 
-acpi_status
-acpi_tb_verify_table_checksum(struct acpi_table_header *table_header);
+void
+acpi_tb_print_table_header(acpi_physical_address address,
+                          struct acpi_table_header *header);
 
-u8 acpi_tb_sum_table(void *buffer, u32 length);
+u8 acpi_tb_checksum(u8 * buffer, acpi_native_uint length);
 
-u8 acpi_tb_generate_checksum(struct acpi_table_header *table);
+acpi_status
+acpi_tb_verify_checksum(struct acpi_table_header *table, u32 length);
 
-void acpi_tb_set_checksum(struct acpi_table_header *table);
+void
+acpi_tb_install_table(acpi_physical_address address,
+                     u8 flags, char *signature, acpi_native_uint table_index);
 
 acpi_status
-acpi_tb_validate_table_header(struct acpi_table_header *table_header);
+acpi_tb_parse_root_table(acpi_physical_address rsdp_address, u8 flags);
 
 #endif                         /* __ACTABLES_H__ */
index b125cee..09469e7 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * Values for description table header signatures. Useful because they make
  * it more difficult to inadvertently type in the wrong signature.
  */
-#define DSDT_SIG                "DSDT" /* Differentiated System Description Table */
-#define FADT_SIG                "FACP" /* Fixed ACPI Description Table */
-#define FACS_SIG                "FACS" /* Firmware ACPI Control Structure */
-#define PSDT_SIG                "PSDT" /* Persistent System Description Table */
-#define RSDP_SIG                "RSD PTR "     /* Root System Description Pointer */
-#define RSDT_SIG                "RSDT" /* Root System Description Table */
-#define XSDT_SIG                "XSDT" /* Extended  System Description Table */
-#define SSDT_SIG                "SSDT" /* Secondary System Description Table */
-#define RSDP_NAME               "RSDP"
+#define ACPI_SIG_DSDT           "DSDT" /* Differentiated System Description Table */
+#define ACPI_SIG_FADT           "FACP" /* Fixed ACPI Description Table */
+#define ACPI_SIG_FACS           "FACS" /* Firmware ACPI Control Structure */
+#define ACPI_SIG_PSDT           "PSDT" /* Persistent System Description Table */
+#define ACPI_SIG_RSDP           "RSD PTR "     /* Root System Description Pointer */
+#define ACPI_SIG_RSDT           "RSDT" /* Root System Description Table */
+#define ACPI_SIG_XSDT           "XSDT" /* Extended  System Description Table */
+#define ACPI_SIG_SSDT           "SSDT" /* Secondary System Description Table */
+#define ACPI_RSDP_NAME          "RSDP" /* Short name for RSDP, not signature */
 
 /*
  * All tables and structures must be byte-packed to match the ACPI
  *
  ******************************************************************************/
 
-#define ACPI_TABLE_HEADER_DEF \
-       char                            signature[4];           /* ASCII table signature */\
-       u32                             length;                 /* Length of table in bytes, including this header */\
-       u8                              revision;               /* ACPI Specification minor version # */\
-       u8                              checksum;               /* To make sum of entire table == 0 */\
-       char                            oem_id[6];              /* ASCII OEM identification */\
-       char                            oem_table_id[8];        /* ASCII OEM table identification */\
-       u32                             oem_revision;           /* OEM revision number */\
-       char                            asl_compiler_id[4];     /* ASCII ASL compiler vendor ID */\
-       u32                             asl_compiler_revision;  /* ASL compiler version */
-
 struct acpi_table_header {
-ACPI_TABLE_HEADER_DEF};
+       char signature[ACPI_NAME_SIZE]; /* ASCII table signature */
+       u32 length;             /* Length of table in bytes, including this header */
+       u8 revision;            /* ACPI Specification minor version # */
+       u8 checksum;            /* To make sum of entire table == 0 */
+       char oem_id[ACPI_OEM_ID_SIZE];  /* ASCII OEM identification */
+       char oem_table_id[ACPI_OEM_TABLE_ID_SIZE];      /* ASCII OEM table identification */
+       u32 oem_revision;       /* OEM revision number */
+       char asl_compiler_id[ACPI_NAME_SIZE];   /* ASCII ASL compiler vendor ID */
+       u32 asl_compiler_revision;      /* ASL compiler version */
+};
 
 /*
  * GAS - Generic Address Structure (ACPI 2.0+)
+ *
+ * Note: Since this structure is used in the ACPI tables, it is byte aligned.
+ * If misalignment is not supported, access to the Address field must be
+ * performed with care.
  */
 struct acpi_generic_address {
-       u8 address_space_id;    /* Address space where struct or register exists */
-       u8 register_bit_width;  /* Size in bits of given register */
-       u8 register_bit_offset; /* Bit offset within the register */
+       u8 space_id;            /* Address space where struct or register exists */
+       u8 bit_width;           /* Size in bits of given register */
+       u8 bit_offset;          /* Bit offset within the register */
        u8 access_width;        /* Minimum Access size (ACPI 3.0) */
        u64 address;            /* 64-bit address of struct or register */
 };
@@ -114,10 +116,10 @@ struct acpi_generic_address {
  *
  ******************************************************************************/
 
-struct rsdp_descriptor {
+struct acpi_table_rsdp {
        char signature[8];      /* ACPI signature, contains "RSD PTR " */
        u8 checksum;            /* ACPI 1.0 checksum */
-       char oem_id[6];         /* OEM identification */
+       char oem_id[ACPI_OEM_ID_SIZE];  /* OEM identification */
        u8 revision;            /* Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+ */
        u32 rsdt_physical_address;      /* 32-bit physical address of the RSDT */
        u32 length;             /* Table length in bytes, including header (ACPI 2.0+) */
@@ -134,12 +136,14 @@ struct rsdp_descriptor {
  *
  ******************************************************************************/
 
-struct rsdt_descriptor {
-       ACPI_TABLE_HEADER_DEF u32 table_offset_entry[1];        /* Array of pointers to ACPI tables */
+struct acpi_table_rsdt {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u32 table_offset_entry[1];      /* Array of pointers to ACPI tables */
 };
 
-struct xsdt_descriptor {
-       ACPI_TABLE_HEADER_DEF u64 table_offset_entry[1];        /* Array of pointers to ACPI tables */
+struct acpi_table_xsdt {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u64 table_offset_entry[1];      /* Array of pointers to ACPI tables */
 };
 
 /*******************************************************************************
@@ -148,36 +152,27 @@ struct xsdt_descriptor {
  *
  ******************************************************************************/
 
-struct facs_descriptor {
+struct acpi_table_facs {
        char signature[4];      /* ASCII table signature */
        u32 length;             /* Length of structure, in bytes */
        u32 hardware_signature; /* Hardware configuration signature */
        u32 firmware_waking_vector;     /* 32-bit physical address of the Firmware Waking Vector */
        u32 global_lock;        /* Global Lock for shared hardware resources */
-
-       /* Flags (32 bits) */
-
-       u8 S4bios_f:1;          /* 00:    S4BIOS support is present */
-        u8:7;                  /* 01-07: Reserved, must be zero */
-       u8 reserved1[3];        /* 08-31: Reserved, must be zero */
-
+       u32 flags;
        u64 xfirmware_waking_vector;    /* 64-bit version of the Firmware Waking Vector (ACPI 2.0+) */
        u8 version;             /* Version of this table (ACPI 2.0+) */
        u8 reserved[31];        /* Reserved, must be zero */
 };
 
+/* Flag macros */
+
+#define ACPI_FACS_S4_BIOS_PRESENT (1)  /* 00: S4BIOS support is present */
+
+/* Global lock flags */
+
 #define ACPI_GLOCK_PENDING      0x01   /* 00: Pending global lock ownership */
 #define ACPI_GLOCK_OWNED        0x02   /* 01: Global lock is owned */
 
-/*
- * Common FACS - This is a version-independent FACS structure used for internal use only
- */
-struct acpi_common_facs {
-       u32 *global_lock;
-       u64 *firmware_waking_vector;
-       u8 vector_width;
-};
-
 /*******************************************************************************
  *
  * FADT - Fixed ACPI Description Table (Signature "FACP")
@@ -186,121 +181,98 @@ struct acpi_common_facs {
 
 /* Fields common to all versions of the FADT */
 
-#define ACPI_FADT_COMMON \
-       ACPI_TABLE_HEADER_DEF \
-       u32                             V1_firmware_ctrl;   /* 32-bit physical address of FACS */ \
-       u32                             V1_dsdt;            /* 32-bit physical address of DSDT */ \
-       u8                              reserved1;          /* System Interrupt Model isn't used in ACPI 2.0*/ \
-       u8                              prefer_PM_profile;  /* Conveys preferred power management profile to OSPM. */ \
-       u16                             sci_int;            /* System vector of SCI interrupt */ \
-       u32                             smi_cmd;            /* Port address of SMI command port */ \
-       u8                              acpi_enable;        /* Value to write to smi_cmd to enable ACPI */ \
-       u8                              acpi_disable;       /* Value to write to smi_cmd to disable ACPI */ \
-       u8                              S4bios_req;         /* Value to write to SMI CMD to enter S4BIOS state */ \
-       u8                              pstate_cnt;         /* Processor performance state control*/ \
-       u32                             V1_pm1a_evt_blk;    /* Port address of Power Mgt 1a Event Reg Blk */ \
-       u32                             V1_pm1b_evt_blk;    /* Port address of Power Mgt 1b Event Reg Blk */ \
-       u32                             V1_pm1a_cnt_blk;    /* Port address of Power Mgt 1a Control Reg Blk */ \
-       u32                             V1_pm1b_cnt_blk;    /* Port address of Power Mgt 1b Control Reg Blk */ \
-       u32                             V1_pm2_cnt_blk;     /* Port address of Power Mgt 2 Control Reg Blk */ \
-       u32                             V1_pm_tmr_blk;      /* Port address of Power Mgt Timer Ctrl Reg Blk */ \
-       u32                             V1_gpe0_blk;        /* Port addr of General Purpose acpi_event 0 Reg Blk */ \
-       u32                             V1_gpe1_blk;        /* Port addr of General Purpose acpi_event 1 Reg Blk */ \
-       u8                              pm1_evt_len;        /* Byte Length of ports at pm1_x_evt_blk */ \
-       u8                              pm1_cnt_len;        /* Byte Length of ports at pm1_x_cnt_blk */ \
-       u8                              pm2_cnt_len;        /* Byte Length of ports at pm2_cnt_blk */ \
-       u8                              pm_tm_len;          /* Byte Length of ports at pm_tm_blk */ \
-       u8                              gpe0_blk_len;       /* Byte Length of ports at gpe0_blk */ \
-       u8                              gpe1_blk_len;       /* Byte Length of ports at gpe1_blk */ \
-       u8                              gpe1_base;          /* Offset in gpe model where gpe1 events start */ \
-       u8                              cst_cnt;            /* Support for the _CST object and C States change notification.*/ \
-       u16                             plvl2_lat;          /* Worst case HW latency to enter/exit C2 state */ \
-       u16                             plvl3_lat;          /* Worst case HW latency to enter/exit C3 state */ \
-       u16                             flush_size;         /* Processor's memory cache line width, in bytes */ \
-       u16                             flush_stride;       /* Number of flush strides that need to be read */ \
-       u8                              duty_offset;        /* Processor's duty cycle index in processor's P_CNT reg*/ \
-       u8                              duty_width;         /* Processor's duty cycle value bit width in P_CNT register.*/ \
-       u8                              day_alrm;           /* Index to day-of-month alarm in RTC CMOS RAM */ \
-       u8                              mon_alrm;           /* Index to month-of-year alarm in RTC CMOS RAM */ \
-       u8                              century;            /* Index to century in RTC CMOS RAM */ \
-       u16                             iapc_boot_arch;     /* IA-PC Boot Architecture Flags. See Table 5-10 for description*/ \
-       u8                              reserved2;          /* Reserved, must be zero */
-
-/*
- * ACPI 2.0+ FADT
- */
-struct fadt_descriptor {
-       ACPI_FADT_COMMON
-           /* Flags (32 bits) */
-       u8 wb_invd:1;           /* 00:    The wbinvd instruction works properly */
-       u8 wb_invd_flush:1;     /* 01:    The wbinvd flushes but does not invalidate */
-       u8 proc_c1:1;           /* 02:    All processors support C1 state */
-       u8 plvl2_up:1;          /* 03:    C2 state works on MP system */
-       u8 pwr_button:1;        /* 04:    Power button is handled as a generic feature */
-       u8 sleep_button:1;      /* 05:    Sleep button is handled as a generic feature, or not present */
-       u8 fixed_rTC:1;         /* 06:    RTC wakeup stat not in fixed register space */
-       u8 rtcs4:1;             /* 07:    RTC wakeup stat not possible from S4 */
-       u8 tmr_val_ext:1;       /* 08:    tmr_val is 32 bits 0=24-bits */
-       u8 dock_cap:1;          /* 09:    Docking supported */
-       u8 reset_reg_sup:1;     /* 10:    System reset via the FADT RESET_REG supported */
-       u8 sealed_case:1;       /* 11:    No internal expansion capabilities and case is sealed */
-       u8 headless:1;          /* 12:    No local video capabilities or local input devices */
-       u8 cpu_sw_sleep:1;      /* 13:    Must execute native instruction after writing SLP_TYPx register */
-
-       u8 pci_exp_wak:1;       /* 14:    System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */
-       u8 use_platform_clock:1;        /* 15:    OSPM should use platform-provided timer (ACPI 3.0) */
-       u8 S4rtc_sts_valid:1;   /* 16:    Contents of RTC_STS valid after S4 wake (ACPI 3.0) */
-       u8 remote_power_on_capable:1;   /* 17:    System is compatible with remote power on (ACPI 3.0) */
-       u8 force_apic_cluster_model:1;  /* 18:    All local APICs must use cluster model (ACPI 3.0) */
-       u8 force_apic_physical_destination_mode:1;      /* 19:   All local x_aPICs must use physical dest mode (ACPI 3.0) */
-        u8:4;                  /* 20-23: Reserved, must be zero */
-       u8 reserved3;           /* 24-31: Reserved, must be zero */
-
-       struct acpi_generic_address reset_register;     /* Reset register address in GAS format */
+struct acpi_table_fadt {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u32 facs;               /* 32-bit physical address of FACS */
+       u32 dsdt;               /* 32-bit physical address of DSDT */
+       u8 model;               /* System Interrupt Model (ACPI 1.0) - not used in ACPI 2.0+ */
+       u8 preferred_profile;   /* Conveys preferred power management profile to OSPM. */
+       u16 sci_interrupt;      /* System vector of SCI interrupt */
+       u32 smi_command;        /* 32-bit Port address of SMI command port */
+       u8 acpi_enable;         /* Value to write to smi_cmd to enable ACPI */
+       u8 acpi_disable;        /* Value to write to smi_cmd to disable ACPI */
+       u8 S4bios_request;      /* Value to write to SMI CMD to enter S4BIOS state */
+       u8 pstate_control;      /* Processor performance state control */
+       u32 pm1a_event_block;   /* 32-bit Port address of Power Mgt 1a Event Reg Blk */
+       u32 pm1b_event_block;   /* 32-bit Port address of Power Mgt 1b Event Reg Blk */
+       u32 pm1a_control_block; /* 32-bit Port address of Power Mgt 1a Control Reg Blk */
+       u32 pm1b_control_block; /* 32-bit Port address of Power Mgt 1b Control Reg Blk */
+       u32 pm2_control_block;  /* 32-bit Port address of Power Mgt 2 Control Reg Blk */
+       u32 pm_timer_block;     /* 32-bit Port address of Power Mgt Timer Ctrl Reg Blk */
+       u32 gpe0_block;         /* 32-bit Port address of General Purpose Event 0 Reg Blk */
+       u32 gpe1_block;         /* 32-bit Port address of General Purpose Event 1 Reg Blk */
+       u8 pm1_event_length;    /* Byte Length of ports at pm1x_event_block */
+       u8 pm1_control_length;  /* Byte Length of ports at pm1x_control_block */
+       u8 pm2_control_length;  /* Byte Length of ports at pm2_control_block */
+       u8 pm_timer_length;     /* Byte Length of ports at pm_timer_block */
+       u8 gpe0_block_length;   /* Byte Length of ports at gpe0_block */
+       u8 gpe1_block_length;   /* Byte Length of ports at gpe1_block */
+       u8 gpe1_base;           /* Offset in GPE number space where GPE1 events start */
+       u8 cst_control;         /* Support for the _CST object and C States change notification */
+       u16 C2latency;          /* Worst case HW latency to enter/exit C2 state */
+       u16 C3latency;          /* Worst case HW latency to enter/exit C3 state */
+       u16 flush_size;         /* Processor's memory cache line width, in bytes */
+       u16 flush_stride;       /* Number of flush strides that need to be read */
+       u8 duty_offset;         /* Processor duty cycle index in processor's P_CNT reg */
+       u8 duty_width;          /* Processor duty cycle value bit width in P_CNT register. */
+       u8 day_alarm;           /* Index to day-of-month alarm in RTC CMOS RAM */
+       u8 month_alarm;         /* Index to month-of-year alarm in RTC CMOS RAM */
+       u8 century;             /* Index to century in RTC CMOS RAM */
+       u16 boot_flags;         /* IA-PC Boot Architecture Flags. See Table 5-10 for description */
+       u8 reserved;            /* Reserved, must be zero */
+       u32 flags;              /* Miscellaneous flag bits (see below for individual flags) */
+       struct acpi_generic_address reset_register;     /* 64-bit address of the Reset register */
        u8 reset_value;         /* Value to write to the reset_register port to reset the system */
-       u8 reserved4[3];        /* These three bytes must be zero */
-       u64 xfirmware_ctrl;     /* 64-bit physical address of FACS */
+       u8 reserved4[3];        /* Reserved, must be zero */
+       u64 Xfacs;              /* 64-bit physical address of FACS */
        u64 Xdsdt;              /* 64-bit physical address of DSDT */
-       struct acpi_generic_address xpm1a_evt_blk;      /* Extended Power Mgt 1a acpi_event Reg Blk address */
-       struct acpi_generic_address xpm1b_evt_blk;      /* Extended Power Mgt 1b acpi_event Reg Blk address */
-       struct acpi_generic_address xpm1a_cnt_blk;      /* Extended Power Mgt 1a Control Reg Blk address */
-       struct acpi_generic_address xpm1b_cnt_blk;      /* Extended Power Mgt 1b Control Reg Blk address */
-       struct acpi_generic_address xpm2_cnt_blk;       /* Extended Power Mgt 2 Control Reg Blk address */
-       struct acpi_generic_address xpm_tmr_blk;        /* Extended Power Mgt Timer Ctrl Reg Blk address */
-       struct acpi_generic_address xgpe0_blk;  /* Extended General Purpose acpi_event 0 Reg Blk address */
-       struct acpi_generic_address xgpe1_blk;  /* Extended General Purpose acpi_event 1 Reg Blk address */
+       struct acpi_generic_address xpm1a_event_block;  /* 64-bit Extended Power Mgt 1a Event Reg Blk address */
+       struct acpi_generic_address xpm1b_event_block;  /* 64-bit Extended Power Mgt 1b Event Reg Blk address */
+       struct acpi_generic_address xpm1a_control_block;        /* 64-bit Extended Power Mgt 1a Control Reg Blk address */
+       struct acpi_generic_address xpm1b_control_block;        /* 64-bit Extended Power Mgt 1b Control Reg Blk address */
+       struct acpi_generic_address xpm2_control_block; /* 64-bit Extended Power Mgt 2 Control Reg Blk address */
+       struct acpi_generic_address xpm_timer_block;    /* 64-bit Extended Power Mgt Timer Ctrl Reg Blk address */
+       struct acpi_generic_address xgpe0_block;        /* 64-bit Extended General Purpose Event 0 Reg Blk address */
+       struct acpi_generic_address xgpe1_block;        /* 64-bit Extended General Purpose Event 1 Reg Blk address */
 };
 
-/*
- * "Down-revved" ACPI 2.0 FADT descriptor
- * Defined here to allow compiler to generate the length of the struct
- */
-struct fadt_descriptor_rev2_minus {
-       ACPI_FADT_COMMON u32 flags;
-       struct acpi_generic_address reset_register;     /* Reset register address in GAS format */
-       u8 reset_value;         /* Value to write to the reset_register port to reset the system. */
-       u8 reserved7[3];        /* Reserved, must be zero */
-};
+/* FADT flags */
+
+#define ACPI_FADT_WBINVD            (1)        /* 00: The wbinvd instruction works properly */
+#define ACPI_FADT_WBINVD_FLUSH      (1<<1)     /* 01: The wbinvd flushes but does not invalidate */
+#define ACPI_FADT_C1_SUPPORTED      (1<<2)     /* 02: All processors support C1 state */
+#define ACPI_FADT_C2_MP_SUPPORTED   (1<<3)     /* 03: C2 state works on MP system */
+#define ACPI_FADT_POWER_BUTTON      (1<<4)     /* 04: Power button is handled as a generic feature */
+#define ACPI_FADT_SLEEP_BUTTON      (1<<5)     /* 05: Sleep button is handled as a generic feature, or  not present */
+#define ACPI_FADT_FIXED_RTC         (1<<6)     /* 06: RTC wakeup stat not in fixed register space */
+#define ACPI_FADT_S4_RTC_WAKE       (1<<7)     /* 07: RTC wakeup stat not possible from S4 */
+#define ACPI_FADT_32BIT_TIMER       (1<<8)     /* 08: tmr_val is 32 bits 0=24-bits */
+#define ACPI_FADT_DOCKING_SUPPORTED (1<<9)     /* 09: Docking supported */
+#define ACPI_FADT_RESET_REGISTER    (1<<10)    /* 10: System reset via the FADT RESET_REG supported */
+#define ACPI_FADT_SEALED_CASE       (1<<11)    /* 11: No internal expansion capabilities and case is sealed */
+#define ACPI_FADT_HEADLESS          (1<<12)    /* 12: No local video capabilities or local input devices */
+#define ACPI_FADT_SLEEP_TYPE        (1<<13)    /* 13: Must execute native instruction after writing  SLP_TYPx register */
+#define ACPI_FADT_PCI_EXPRESS_WAKE  (1<<14)    /* 14: System supports PCIEXP_WAKE (STS/EN) bits (ACPI 3.0) */
+#define ACPI_FADT_PLATFORM_CLOCK    (1<<15)    /* 15: OSPM should use platform-provided timer (ACPI 3.0) */
+#define ACPI_FADT_S4_RTC_VALID      (1<<16)    /* 16: Contents of RTC_STS valid after S4 wake (ACPI 3.0) */
+#define ACPI_FADT_REMOTE_POWER_ON   (1<<17)    /* 17: System is compatible with remote power on (ACPI 3.0) */
+#define ACPI_FADT_APIC_CLUSTER      (1<<18)    /* 18: All local APICs must use cluster model (ACPI 3.0) */
+#define ACPI_FADT_APIC_PHYSICAL     (1<<19)    /* 19: All local x_aPICs must use physical dest mode (ACPI 3.0) */
 
 /*
- * ACPI 1.0 FADT
- * Defined here to allow compiler to generate the length of the struct
+ * FADT Prefered Power Management Profiles
  */
-struct fadt_descriptor_rev1 {
-       ACPI_FADT_COMMON u32 flags;
+enum acpi_prefered_pm_profiles {
+       PM_UNSPECIFIED = 0,
+       PM_DESKTOP = 1,
+       PM_MOBILE = 2,
+       PM_WORKSTATION = 3,
+       PM_ENTERPRISE_SERVER = 4,
+       PM_SOHO_SERVER = 5,
+       PM_APPLIANCE_PC = 6
 };
 
-/* FADT: Prefered Power Management Profiles */
-
-#define PM_UNSPECIFIED                  0
-#define PM_DESKTOP                      1
-#define PM_MOBILE                       2
-#define PM_WORKSTATION                  3
-#define PM_ENTERPRISE_SERVER            4
-#define PM_SOHO_SERVER                  5
-#define PM_APPLIANCE_PC                 6
-
-/* FADT: Boot Arch Flags */
+/* FADT Boot Arch Flags */
 
 #define BAF_LEGACY_DEVICES              0x0001
 #define BAF_8042_KEYBOARD_CONTROLLER    0x0002
@@ -312,59 +284,12 @@ struct fadt_descriptor_rev1 {
 
 #pragma pack()
 
-/*
- * This macro is temporary until the table bitfield flag definitions
- * are removed and replaced by a Flags field.
- */
-#define ACPI_FLAG_OFFSET(d,f,o)         (u8) (ACPI_OFFSET (d,f) + \
-                         sizeof(((d *)0)->f) + o)
-/*
- * Get the remaining ACPI tables
- */
-#include "actbl1.h"
+#define ACPI_FADT_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_fadt, f)
 
 /*
- * ACPI Table information.  We save the table address, length,
- * and type of memory allocation (mapped or allocated) for each
- * table for 1) when we exit, and 2) if a new table is installed
+ * Get the remaining ACPI tables
  */
-#define ACPI_MEM_NOT_ALLOCATED  0
-#define ACPI_MEM_ALLOCATED      1
-#define ACPI_MEM_MAPPED         2
-
-/* Definitions for the Flags bitfield member of struct acpi_table_support */
-
-#define ACPI_TABLE_SINGLE       0x00
-#define ACPI_TABLE_MULTIPLE     0x01
-#define ACPI_TABLE_EXECUTABLE   0x02
-
-#define ACPI_TABLE_ROOT         0x00
-#define ACPI_TABLE_PRIMARY      0x10
-#define ACPI_TABLE_SECONDARY    0x20
-#define ACPI_TABLE_ALL          0x30
-#define ACPI_TABLE_TYPE_MASK    0x30
-
-/* Data about each known table type */
-
-struct acpi_table_support {
-       char *name;
-       char *signature;
-       void **global_ptr;
-       u8 sig_length;
-       u8 flags;
-};
-
-extern u8 acpi_fadt_is_v1;     /* is set to 1 if FADT is revision 1,
-                                * needed for certain workarounds */
-/* Macros used to generate offsets to specific table fields */
-
-#define ACPI_FACS_OFFSET(f)             (u8) ACPI_OFFSET (struct facs_descriptor,f)
-#define ACPI_FADT_OFFSET(f)             (u8) ACPI_OFFSET (struct fadt_descriptor, f)
-#define ACPI_GAS_OFFSET(f)              (u8) ACPI_OFFSET (struct acpi_generic_address,f)
-#define ACPI_HDR_OFFSET(f)              (u8) ACPI_OFFSET (struct acpi_table_header,f)
-#define ACPI_RSDP_OFFSET(f)             (u8) ACPI_OFFSET (struct rsdp_descriptor,f)
 
-#define ACPI_FADT_FLAG_OFFSET(f,o)      ACPI_FLAG_OFFSET (struct fadt_descriptor,f,o)
-#define ACPI_FACS_FLAG_OFFSET(f,o)      ACPI_FLAG_OFFSET (struct facs_descriptor,f,o)
+#include <acpi/actbl1.h>
 
 #endif                         /* __ACTBL_H__ */
index 745a644..4e5d3ca 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -61,6 +61,7 @@
 #define ACPI_SIG_BOOT           "BOOT" /* Simple Boot Flag Table */
 #define ACPI_SIG_CPEP           "CPEP" /* Corrected Platform Error Polling table */
 #define ACPI_SIG_DBGP           "DBGP" /* Debug Port table */
+#define ACPI_SIG_DMAR           "DMAR" /* DMA Remapping table */
 #define ACPI_SIG_ECDT           "ECDT" /* Embedded Controller Boot Resources Table */
 #define ACPI_SIG_HPET           "HPET" /* High Precision Event Timer table */
 #define ACPI_SIG_MADT           "APIC" /* Multiple APIC Description Table */
 #define ACPI_SIG_TCPA           "TCPA" /* Trusted Computing Platform Alliance table */
 #define ACPI_SIG_WDRT           "WDRT" /* Watchdog Resource Table */
 
-/* Legacy names */
-
-#define APIC_SIG                "APIC" /* Multiple APIC Description Table */
-#define BOOT_SIG                "BOOT" /* Simple Boot Flag Table */
-#define SBST_SIG                "SBST" /* Smart Battery Specification Table */
-
 /*
  * All tables must be byte-packed to match the ACPI specification, since
  * the tables are provided by the system BIOS.
  * portable, so do not use any other bitfield types.
  */
 
+/* Common Sub-table header (used in MADT, SRAT, etc.) */
+
+struct acpi_subtable_header {
+       u8 type;
+       u8 length;
+};
+
 /*******************************************************************************
  *
  * ASF - Alert Standard Format table (Signature "ASF!")
  *
+ * Conforms to the Alert Standard Format Specification V2.0, 23 April 2003
+ *
  ******************************************************************************/
 
 struct acpi_table_asf {
-ACPI_TABLE_HEADER_DEF};
+       struct acpi_table_header header;        /* Common ACPI table header */
+};
 
-#define ACPI_ASF_HEADER_DEF \
-       u8                              type; \
-       u8                              reserved; \
-       u16                             length;
+/* ASF subtable header */
 
 struct acpi_asf_header {
-ACPI_ASF_HEADER_DEF};
+       u8 type;
+       u8 reserved;
+       u16 length;
+};
 
-/* Values for Type field */
+/* Values for Type field above */
 
-#define ASF_INFO                0
-#define ASF_ALERT               1
-#define ASF_CONTROL             2
-#define ASF_BOOT                3
-#define ASF_ADDRESS             4
-#define ASF_RESERVED            5
+enum acpi_asf_type {
+       ACPI_ASF_TYPE_INFO = 0,
+       ACPI_ASF_TYPE_ALERT = 1,
+       ACPI_ASF_TYPE_CONTROL = 2,
+       ACPI_ASF_TYPE_BOOT = 3,
+       ACPI_ASF_TYPE_ADDRESS = 4,
+       ACPI_ASF_TYPE_RESERVED = 5
+};
 
 /*
  * ASF subtables
@@ -124,7 +131,8 @@ ACPI_ASF_HEADER_DEF};
 /* 0: ASF Information */
 
 struct acpi_asf_info {
-       ACPI_ASF_HEADER_DEF u8 min_reset_value;
+       struct acpi_asf_header header;
+       u8 min_reset_value;
        u8 min_poll_interval;
        u16 system_id;
        u32 mfg_id;
@@ -135,26 +143,49 @@ struct acpi_asf_info {
 /* 1: ASF Alerts */
 
 struct acpi_asf_alert {
-       ACPI_ASF_HEADER_DEF u8 assert_mask;
+       struct acpi_asf_header header;
+       u8 assert_mask;
        u8 deassert_mask;
        u8 alerts;
        u8 data_length;
-       u8 array[1];
+};
+
+struct acpi_asf_alert_data {
+       u8 address;
+       u8 command;
+       u8 mask;
+       u8 value;
+       u8 sensor_type;
+       u8 type;
+       u8 offset;
+       u8 source_type;
+       u8 severity;
+       u8 sensor_number;
+       u8 entity;
+       u8 instance;
 };
 
 /* 2: ASF Remote Control */
 
 struct acpi_asf_remote {
-       ACPI_ASF_HEADER_DEF u8 controls;
+       struct acpi_asf_header header;
+       u8 controls;
        u8 data_length;
        u16 reserved2;
-       u8 array[1];
+};
+
+struct acpi_asf_control_data {
+       u8 function;
+       u8 address;
+       u8 command;
+       u8 value;
 };
 
 /* 3: ASF RMCP Boot Options */
 
 struct acpi_asf_rmcp {
-       ACPI_ASF_HEADER_DEF u8 capabilities[7];
+       struct acpi_asf_header header;
+       u8 capabilities[7];
        u8 completion_code;
        u32 enterprise_id;
        u8 command;
@@ -166,9 +197,9 @@ struct acpi_asf_rmcp {
 /* 4: ASF Address */
 
 struct acpi_asf_address {
-       ACPI_ASF_HEADER_DEF u8 eprom_address;
+       struct acpi_asf_header header;
+       u8 eprom_address;
        u8 devices;
-       u8 smbus_addresses[1];
 };
 
 /*******************************************************************************
@@ -178,7 +209,8 @@ struct acpi_asf_address {
  ******************************************************************************/
 
 struct acpi_table_boot {
-       ACPI_TABLE_HEADER_DEF u8 cmos_index;    /* Index in CMOS RAM for the boot register */
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u8 cmos_index;          /* Index in CMOS RAM for the boot register */
        u8 reserved[3];
 };
 
@@ -189,7 +221,8 @@ struct acpi_table_boot {
  ******************************************************************************/
 
 struct acpi_table_cpep {
-       ACPI_TABLE_HEADER_DEF u64 reserved;
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u64 reserved;
 };
 
 /* Subtable */
@@ -197,9 +230,9 @@ struct acpi_table_cpep {
 struct acpi_cpep_polling {
        u8 type;
        u8 length;
-       u8 processor_id;        /* Processor ID */
-       u8 processor_eid;       /* Processor EID */
-       u32 polling_interval;   /* Polling interval (msec) */
+       u8 id;                  /* Processor ID */
+       u8 eid;                 /* Processor EID */
+       u32 interval;           /* Polling interval (msec) */
 };
 
 /*******************************************************************************
@@ -209,196 +242,281 @@ struct acpi_cpep_polling {
  ******************************************************************************/
 
 struct acpi_table_dbgp {
-       ACPI_TABLE_HEADER_DEF u8 interface_type;        /* 0=full 16550, 1=subset of 16550 */
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u8 type;                /* 0=full 16550, 1=subset of 16550 */
        u8 reserved[3];
        struct acpi_generic_address debug_port;
 };
 
 /*******************************************************************************
  *
- * ECDT - Embedded Controller Boot Resources Table
+ * DMAR - DMA Remapping table
  *
  ******************************************************************************/
 
-struct ec_boot_resources {
-       ACPI_TABLE_HEADER_DEF struct acpi_generic_address ec_control;   /* Address of EC command/status register */
-       struct acpi_generic_address ec_data;    /* Address of EC data register */
-       u32 uid;                /* Unique ID - must be same as the EC _UID method */
-       u8 gpe_bit;             /* The GPE for the EC */
-       u8 ec_id[1];            /* Full namepath of the EC in the ACPI namespace */
+struct acpi_table_dmar {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u8 width;               /* Host Address Width */
+       u8 reserved[11];
+};
+
+/* DMAR subtable header */
+
+struct acpi_dmar_header {
+       u16 type;
+       u16 length;
+       u8 flags;
+       u8 reserved[3];
+};
+
+/* Values for subtable type in struct acpi_dmar_header */
+
+enum acpi_dmar_type {
+       ACPI_DMAR_TYPE_HARDWARE_UNIT = 0,
+       ACPI_DMAR_TYPE_RESERVED_MEMORY = 1,
+       ACPI_DMAR_TYPE_RESERVED = 2     /* 2 and greater are reserved */
+};
+
+struct acpi_dmar_device_scope {
+       u8 entry_type;
+       u8 length;
+       u8 segment;
+       u8 bus;
+};
+
+/* Values for entry_type in struct acpi_dmar_device_scope */
+
+enum acpi_dmar_scope_type {
+       ACPI_DMAR_SCOPE_TYPE_NOT_USED = 0,
+       ACPI_DMAR_SCOPE_TYPE_ENDPOINT = 1,
+       ACPI_DMAR_SCOPE_TYPE_BRIDGE = 2,
+       ACPI_DMAR_SCOPE_TYPE_RESERVED = 3       /* 3 and greater are reserved */
+};
+
+/*
+ * DMAR Sub-tables, correspond to Type in struct acpi_dmar_header
+ */
+
+/* 0: Hardware Unit Definition */
+
+struct acpi_dmar_hardware_unit {
+       struct acpi_dmar_header header;
+       u64 address;            /* Register Base Address */
+};
+
+/* Flags */
+
+#define ACPI_DMAR_INCLUDE_ALL       (1)
+
+/* 1: Reserved Memory Defininition */
+
+struct acpi_dmar_reserved_memory {
+       struct acpi_dmar_header header;
+       u64 address;            /* 4_k aligned base address */
+       u64 end_address;        /* 4_k aligned limit address */
 };
 
+/* Flags */
+
+#define ACPI_DMAR_ALLOW_ALL         (1)
+
 /*******************************************************************************
  *
- * HPET - High Precision Event Timer table
+ * ECDT - Embedded Controller Boot Resources Table
  *
  ******************************************************************************/
 
-struct acpi_hpet_table {
-       ACPI_TABLE_HEADER_DEF u32 hardware_id;  /* Hardware ID of event timer block */
-       struct acpi_generic_address base_address;       /* Address of event timer block */
-       u8 hpet_number;         /* HPET sequence number */
-       u16 clock_tick;         /* Main counter min tick, periodic mode */
-       u8 attributes;
+struct acpi_table_ecdt {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       struct acpi_generic_address control;    /* Address of EC command/status register */
+       struct acpi_generic_address data;       /* Address of EC data register */
+       u32 uid;                /* Unique ID - must be same as the EC _UID method */
+       u8 gpe;                 /* The GPE for the EC */
+       u8 id[1];               /* Full namepath of the EC in the ACPI namespace */
 };
 
-#if 0                          /* HPET flags to be converted to macros */
-struct {                       /* Flags (8 bits) */
-       u8 page_protect:1;      /* 00:    No page protection */
-       u8 page_protect4:1;     /* 01:    4_kB page protected */
-       u8 page_protect64:1;    /* 02:    64_kB page protected */
-        u8:5;                  /* 03-07: Reserved, must be zero */
-} flags;
-#endif
-
 /*******************************************************************************
  *
- * MADT - Multiple APIC Description Table
+ * HPET - High Precision Event Timer table
  *
  ******************************************************************************/
 
-struct multiple_apic_table {
-       ACPI_TABLE_HEADER_DEF u32 local_apic_address;   /* Physical address of local APIC */
-
-       /* Flags (32 bits) */
-
-       u8 PCATcompat:1;        /* 00:    System also has dual 8259s */
-        u8:7;                  /* 01-07: Reserved, must be zero */
-       u8 reserved1[3];        /* 08-31: Reserved, must be zero */
+struct acpi_table_hpet {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u32 id;                 /* Hardware ID of event timer block */
+       struct acpi_generic_address address;    /* Address of event timer block */
+       u8 sequence;            /* HPET sequence number */
+       u16 minimum_tick;       /* Main counter min tick, periodic mode */
+       u8 flags;
 };
 
-/* Values for MADT PCATCompat */
+/*! Flags */
 
-#define DUAL_PIC                0
-#define MULTIPLE_APIC           1
+#define ACPI_HPET_PAGE_PROTECT      (1)        /* 00: No page protection */
+#define ACPI_HPET_PAGE_PROTECT_4    (1<<1)     /* 01: 4KB page protected */
+#define ACPI_HPET_PAGE_PROTECT_64   (1<<2)     /* 02: 64KB page protected */
 
-/* Common MADT Sub-table header */
+/*! [End] no source code translation !*/
 
-#define APIC_HEADER_DEF \
-       u8                              type; \
-       u8                              length;
-
-struct apic_header {
-APIC_HEADER_DEF};
-
-/* Values for Type in struct apic_header */
+/*******************************************************************************
+ *
+ * MADT - Multiple APIC Description Table
+ *
+ ******************************************************************************/
 
-#define APIC_PROCESSOR          0
-#define APIC_IO                 1
-#define APIC_XRUPT_OVERRIDE     2
-#define APIC_NMI                3
-#define APIC_LOCAL_NMI          4
-#define APIC_ADDRESS_OVERRIDE   5
-#define APIC_IO_SAPIC           6
-#define APIC_LOCAL_SAPIC        7
-#define APIC_XRUPT_SOURCE       8
-#define APIC_RESERVED           9      /* 9 and greater are reserved */
+struct acpi_table_madt {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u32 address;            /* Physical address of local APIC */
+       u32 flags;
+};
 
-/* Flag definitions for MADT sub-tables */
+/* Flags */
 
-#define ACPI_MADT_IFLAGS /* INTI flags (16 bits) */ \
-       u8                              polarity        : 2;    /* 00-01: Polarity of APIC I/O input signals */\
-       u8                              trigger_mode    : 2;    /* 02-03: Trigger mode of APIC input signals */\
-       u8                                              : 4;    /* 04-07: Reserved, must be zero */\
-       u8                              reserved1;      /* 08-15: Reserved, must be zero */
+#define ACPI_MADT_PCAT_COMPAT       (1)        /* 00:    System also has dual 8259s */
 
-#define ACPI_MADT_LFLAGS /* Local Sapic flags (32 bits) */ \
-       u8                              processor_enabled: 1;   /* 00:    Processor is usable if set */\
-       u8                                              : 7;    /* 01-07: Reserved, must be zero */\
-       u8                              reserved2[3];   /* 08-31: Reserved, must be zero */
+/* Values for PCATCompat flag */
 
-/* Values for MPS INTI flags */
+#define ACPI_MADT_DUAL_PIC          0
+#define ACPI_MADT_MULTIPLE_APIC     1
 
-#define POLARITY_CONFORMS       0
-#define POLARITY_ACTIVE_HIGH    1
-#define POLARITY_RESERVED       2
-#define POLARITY_ACTIVE_LOW     3
+/* Values for subtable type in struct acpi_subtable_header */
 
-#define TRIGGER_CONFORMS        0
-#define TRIGGER_EDGE            1
-#define TRIGGER_RESERVED        2
-#define TRIGGER_LEVEL           3
+enum acpi_madt_type {
+       ACPI_MADT_TYPE_LOCAL_APIC = 0,
+       ACPI_MADT_TYPE_IO_APIC = 1,
+       ACPI_MADT_TYPE_INTERRUPT_OVERRIDE = 2,
+       ACPI_MADT_TYPE_NMI_SOURCE = 3,
+       ACPI_MADT_TYPE_LOCAL_APIC_NMI = 4,
+       ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE = 5,
+       ACPI_MADT_TYPE_IO_SAPIC = 6,
+       ACPI_MADT_TYPE_LOCAL_SAPIC = 7,
+       ACPI_MADT_TYPE_INTERRUPT_SOURCE = 8,
+       ACPI_MADT_TYPE_RESERVED = 9     /* 9 and greater are reserved */
+};
 
 /*
- * MADT Sub-tables, correspond to Type in struct apic_header
+ * MADT Sub-tables, correspond to Type in struct acpi_subtable_header
  */
 
-/* 0: processor APIC */
+/* 0: Processor Local APIC */
 
-struct madt_processor_apic {
-       APIC_HEADER_DEF u8 processor_id;        /* ACPI processor id */
-       u8 local_apic_id;       /* Processor's local APIC id */
- ACPI_MADT_LFLAGS};
+struct acpi_madt_local_apic {
+       struct acpi_subtable_header header;
+       u8 processor_id;        /* ACPI processor id */
+       u8 id;                  /* Processor's local APIC id */
+       u32 lapic_flags;
+};
 
 /* 1: IO APIC */
 
-struct madt_io_apic {
-       APIC_HEADER_DEF u8 io_apic_id;  /* I/O APIC ID */
+struct acpi_madt_io_apic {
+       struct acpi_subtable_header header;
+       u8 id;                  /* I/O APIC ID */
        u8 reserved;            /* Reserved - must be zero */
        u32 address;            /* APIC physical address */
-       u32 interrupt;          /* Global system interrupt where INTI lines start */
+       u32 global_irq_base;    /* Global system interrupt where INTI lines start */
 };
 
 /* 2: Interrupt Override */
 
-struct madt_interrupt_override {
-       APIC_HEADER_DEF u8 bus; /* 0 - ISA */
-       u8 source;              /* Interrupt source (IRQ) */
-       u32 interrupt;          /* Global system interrupt */
- ACPI_MADT_IFLAGS};
+struct acpi_madt_interrupt_override {
+       struct acpi_subtable_header header;
+       u8 bus;                 /* 0 - ISA */
+       u8 source_irq;          /* Interrupt source (IRQ) */
+       u32 global_irq;         /* Global system interrupt */
+       u16 inti_flags;
+};
 
-/* 3: NMI Sources */
+/* 3: NMI Source */
 
-struct madt_nmi_source {
-       APIC_HEADER_DEF ACPI_MADT_IFLAGS u32 interrupt; /* Global system interrupt */
+struct acpi_madt_nmi_source {
+       struct acpi_subtable_header header;
+       u16 inti_flags;
+       u32 global_irq;         /* Global system interrupt */
 };
 
 /* 4: Local APIC NMI */
 
-struct madt_local_apic_nmi {
-       APIC_HEADER_DEF u8 processor_id;        /* ACPI processor id */
-       ACPI_MADT_IFLAGS u8 lint;       /* LINTn to which NMI is connected */
+struct acpi_madt_local_apic_nmi {
+       struct acpi_subtable_header header;
+       u8 processor_id;        /* ACPI processor id */
+       u16 inti_flags;
+       u8 lint;                /* LINTn to which NMI is connected */
 };
 
 /* 5: Address Override */
 
-struct madt_address_override {
-       APIC_HEADER_DEF u16 reserved;   /* Reserved, must be zero */
+struct acpi_madt_local_apic_override {
+       struct acpi_subtable_header header;
+       u16 reserved;           /* Reserved, must be zero */
        u64 address;            /* APIC physical address */
 };
 
 /* 6: I/O Sapic */
 
-struct madt_io_sapic {
-       APIC_HEADER_DEF u8 io_sapic_id; /* I/O SAPIC ID */
+struct acpi_madt_io_sapic {
+       struct acpi_subtable_header header;
+       u8 id;                  /* I/O SAPIC ID */
        u8 reserved;            /* Reserved, must be zero */
-       u32 interrupt_base;     /* Glocal interrupt for SAPIC start */
+       u32 global_irq_base;    /* Global interrupt for SAPIC start */
        u64 address;            /* SAPIC physical address */
 };
 
 /* 7: Local Sapic */
 
-struct madt_local_sapic {
-       APIC_HEADER_DEF u8 processor_id;        /* ACPI processor id */
-       u8 local_sapic_id;      /* SAPIC ID */
-       u8 local_sapic_eid;     /* SAPIC EID */
+struct acpi_madt_local_sapic {
+       struct acpi_subtable_header header;
+       u8 processor_id;        /* ACPI processor id */
+       u8 id;                  /* SAPIC ID */
+       u8 eid;                 /* SAPIC EID */
        u8 reserved[3];         /* Reserved, must be zero */
-        ACPI_MADT_LFLAGS u32 processor_uID;    /* Numeric UID - ACPI 3.0 */
-       char processor_uIDstring[1];    /* String UID  - ACPI 3.0 */
+       u32 lapic_flags;
+       u32 uid;                /* Numeric UID - ACPI 3.0 */
+       char uid_string[1];     /* String UID  - ACPI 3.0 */
 };
 
 /* 8: Platform Interrupt Source */
 
-struct madt_interrupt_source {
-       APIC_HEADER_DEF ACPI_MADT_IFLAGS u8 interrupt_type;     /* 1=PMI, 2=INIT, 3=corrected */
-       u8 processor_id;        /* Processor ID */
-       u8 processor_eid;       /* Processor EID */
+struct acpi_madt_interrupt_source {
+       struct acpi_subtable_header header;
+       u16 inti_flags;
+       u8 type;                /* 1=PMI, 2=INIT, 3=corrected */
+       u8 id;                  /* Processor ID */
+       u8 eid;                 /* Processor EID */
        u8 io_sapic_vector;     /* Vector value for PMI interrupts */
-       u32 interrupt;          /* Global system interrupt */
+       u32 global_irq;         /* Global system interrupt */
        u32 flags;              /* Interrupt Source Flags */
 };
 
-#ifdef DUPLICATE_DEFINITION_WITH_LINUX_ACPI_H
+/* Flags field above */
+
+#define ACPI_MADT_CPEI_OVERRIDE     (1)
+
+/*
+ * Common flags fields for MADT subtables
+ */
+
+/* MADT Local APIC flags (lapic_flags) */
+
+#define ACPI_MADT_ENABLED           (1)        /* 00: Processor is usable if set */
+
+/* MADT MPS INTI flags (inti_flags) */
+
+#define ACPI_MADT_POLARITY_MASK     (3)        /* 00-01: Polarity of APIC I/O input signals */
+#define ACPI_MADT_TRIGGER_MASK      (3<<2)     /* 02-03: Trigger mode of APIC input signals */
+
+/* Values for MPS INTI flags */
+
+#define ACPI_MADT_POLARITY_CONFORMS       0
+#define ACPI_MADT_POLARITY_ACTIVE_HIGH    1
+#define ACPI_MADT_POLARITY_RESERVED       2
+#define ACPI_MADT_POLARITY_ACTIVE_LOW     3
+
+#define ACPI_MADT_TRIGGER_CONFORMS        (0)
+#define ACPI_MADT_TRIGGER_EDGE            (1<<2)
+#define ACPI_MADT_TRIGGER_RESERVED        (2<<2)
+#define ACPI_MADT_TRIGGER_LEVEL           (3<<2)
+
 /*******************************************************************************
  *
  * MCFG - PCI Memory Mapped Configuration table and sub-table
@@ -406,17 +524,19 @@ struct madt_interrupt_source {
  ******************************************************************************/
 
 struct acpi_table_mcfg {
-       ACPI_TABLE_HEADER_DEF u8 reserved[8];
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u8 reserved[8];
 };
 
+/* Subtable */
+
 struct acpi_mcfg_allocation {
-       u64 base_address;       /* Base address, processor-relative */
+       u64 address;            /* Base address, processor-relative */
        u16 pci_segment;        /* PCI segment group number */
        u8 start_bus_number;    /* Starting PCI Bus number */
        u8 end_bus_number;      /* Final PCI Bus number */
        u32 reserved;
 };
-#endif
 
 /*******************************************************************************
  *
@@ -424,8 +544,9 @@ struct acpi_mcfg_allocation {
  *
  ******************************************************************************/
 
-struct smart_battery_table {
-       ACPI_TABLE_HEADER_DEF u32 warning_level;
+struct acpi_table_sbst {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u32 warning_level;
        u32 low_level;
        u32 critical_level;
 };
@@ -436,9 +557,10 @@ struct smart_battery_table {
  *
  ******************************************************************************/
 
-struct system_locality_info {
-       ACPI_TABLE_HEADER_DEF u64 locality_count;
-       u8 entry[1][1];
+struct acpi_table_slit {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u64 locality_count;
+       u8 entry[1];            /* Real size = localities^2 */
 };
 
 /*******************************************************************************
@@ -448,7 +570,8 @@ struct system_locality_info {
  ******************************************************************************/
 
 struct acpi_table_spcr {
-       ACPI_TABLE_HEADER_DEF u8 interface_type;        /* 0=full 16550, 1=subset of 16550 */
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u8 interface_type;      /* 0=full 16550, 1=subset of 16550 */
        u8 reserved[3];
        struct acpi_generic_address serial_port;
        u8 interrupt_type;
@@ -459,7 +582,7 @@ struct acpi_table_spcr {
        u8 stop_bits;
        u8 flow_control;
        u8 terminal_type;
-       u8 reserved2;
+       u8 reserved1;
        u16 pci_device_id;
        u16 pci_vendor_id;
        u8 pci_bus;
@@ -467,7 +590,7 @@ struct acpi_table_spcr {
        u8 pci_function;
        u32 pci_flags;
        u8 pci_segment;
-       u32 reserved3;
+       u32 reserved2;
 };
 
 /*******************************************************************************
@@ -477,12 +600,13 @@ struct acpi_table_spcr {
  ******************************************************************************/
 
 struct acpi_table_spmi {
-       ACPI_TABLE_HEADER_DEF u8 reserved;
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u8 reserved;
        u8 interface_type;
        u16 spec_revision;      /* Version of IPMI */
        u8 interrupt_type;
        u8 gpe_number;          /* GPE assigned */
-       u8 reserved2;
+       u8 reserved1;
        u8 pci_device_flag;
        u32 interrupt;
        struct acpi_generic_address ipmi_register;
@@ -498,58 +622,53 @@ struct acpi_table_spmi {
  *
  ******************************************************************************/
 
-struct system_resource_affinity {
-       ACPI_TABLE_HEADER_DEF u32 reserved1;    /* Must be value '1' */
-       u64 reserved2;          /* Reserved, must be zero */
+struct acpi_table_srat {
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u32 table_revision;     /* Must be value '1' */
+       u64 reserved;           /* Reserved, must be zero */
 };
 
-/* SRAT common sub-table header */
+/* Values for subtable type in struct acpi_subtable_header */
 
-#define SRAT_SUBTABLE_HEADER \
-       u8                              type; \
-       u8                              length;
-
-/* Values for Type above */
-
-#define SRAT_CPU_AFFINITY       0
-#define SRAT_MEMORY_AFFINITY    1
-#define SRAT_RESERVED           2
+enum acpi_srat_type {
+       ACPI_SRAT_TYPE_CPU_AFFINITY = 0,
+       ACPI_SRAT_TYPE_MEMORY_AFFINITY = 1,
+       ACPI_SRAT_TYPE_RESERVED = 2
+};
 
 /* SRAT sub-tables */
 
-struct static_resource_alloc {
-       SRAT_SUBTABLE_HEADER u8 proximity_domain_lo;
+struct acpi_srat_cpu_affinity {
+       struct acpi_subtable_header header;
+       u8 proximity_domain_lo;
        u8 apic_id;
-
-       /* Flags (32 bits) */
-
-       u8 enabled:1;           /* 00:    Use affinity structure */
-        u8:7;                  /* 01-07: Reserved, must be zero */
-       u8 reserved3[3];        /* 08-31: Reserved, must be zero */
-
+       u32 flags;
        u8 local_sapic_eid;
        u8 proximity_domain_hi[3];
-       u32 reserved4;          /* Reserved, must be zero */
+       u32 reserved          /* Reserved, must be zero */
 };
 
-struct memory_affinity {
-       SRAT_SUBTABLE_HEADER u32 proximity_domain;
-       u16 reserved3;
-       u64 base_address;
-       u64 address_length;
-       u32 reserved4;
-
-       /* Flags (32 bits) */
+/* Flags */
 
-       u8 enabled:1;           /* 00:    Use affinity structure */
-       u8 hot_pluggable:1;     /* 01:    Memory region is hot pluggable */
-       u8 non_volatile:1;      /* 02:    Memory is non-volatile */
-        u8:5;                  /* 03-07: Reserved, must be zero */
-       u8 reserved5[3];        /* 08-31: Reserved, must be zero */
+#define ACPI_SRAT_CPU_ENABLED       (1)        /* 00: Use affinity structure */
 
-       u64 reserved6;          /* Reserved, must be zero */
+struct acpi_srat_mem_affinity {
+       struct acpi_subtable_header header;
+       u32 proximity_domain;
+       u16 reserved;           /* Reserved, must be zero */
+       u64 base_address;
+       u64 length;
+       u32 memory_type;        /* See acpi_address_range_id */
+       u32 flags;
+       u64 reserved1;          /* Reserved, must be zero */
 };
 
+/* Flags */
+
+#define ACPI_SRAT_MEM_ENABLED       (1)        /* 00: Use affinity structure */
+#define ACPI_SRAT_MEM_HOT_PLUGGABLE (1<<1)     /* 01: Memory region is hot pluggable */
+#define ACPI_SRAT_MEM_NON_VOLATILE  (1<<2)     /* 02: Memory region is non-volatile */
+
 /*******************************************************************************
  *
  * TCPA - Trusted Computing Platform Alliance table
@@ -557,7 +676,8 @@ struct memory_affinity {
  ******************************************************************************/
 
 struct acpi_table_tcpa {
-       ACPI_TABLE_HEADER_DEF u16 reserved;
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u16 reserved;
        u32 max_log_length;     /* Maximum length for the event log area */
        u64 log_address;        /* Address of the event log area */
 };
@@ -569,7 +689,8 @@ struct acpi_table_tcpa {
  ******************************************************************************/
 
 struct acpi_table_wdrt {
-       ACPI_TABLE_HEADER_DEF u32 header_length;        /* Watchdog Header Length */
+       struct acpi_table_header header;        /* Common ACPI table header */
+       u32 header_length;      /* Watchdog Header Length */
        u8 pci_segment;         /* PCI Segment number */
        u8 pci_bus;             /* PCI Bus number */
        u8 pci_device;          /* PCI Device number */
@@ -582,58 +703,9 @@ struct acpi_table_wdrt {
        u32 entries;            /* Number of watchdog entries that follow */
 };
 
-#if 0                          /* Flags, will be converted to macros */
-u8 enabled:1;                  /* 00:    Timer enabled */
-u8:6;                          /* 01-06: Reserved */
-u8 sleep_stop:1;               /* 07:    Timer stopped in sleep state */
-#endif
-
-/* Macros used to generate offsets to specific table fields */
-
-#define ACPI_ASF0_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_asf_info,f)
-#define ACPI_ASF1_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_asf_alert,f)
-#define ACPI_ASF2_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_asf_remote,f)
-#define ACPI_ASF3_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_asf_rmcp,f)
-#define ACPI_ASF4_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_asf_address,f)
-#define ACPI_BOOT_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_boot,f)
-#define ACPI_CPEP_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_cpep,f)
-#define ACPI_CPEP0_OFFSET(f)            (u8) ACPI_OFFSET (struct acpi_cpep_polling,f)
-#define ACPI_DBGP_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_dbgp,f)
-#define ACPI_ECDT_OFFSET(f)             (u8) ACPI_OFFSET (struct ec_boot_resources,f)
-#define ACPI_HPET_OFFSET(f)             (u8) ACPI_OFFSET (struct hpet_table,f)
-#define ACPI_MADT_OFFSET(f)             (u8) ACPI_OFFSET (struct multiple_apic_table,f)
-#define ACPI_MADT0_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_processor_apic,f)
-#define ACPI_MADT1_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_io_apic,f)
-#define ACPI_MADT2_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_interrupt_override,f)
-#define ACPI_MADT3_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_nmi_source,f)
-#define ACPI_MADT4_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_local_apic_nmi,f)
-#define ACPI_MADT5_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_address_override,f)
-#define ACPI_MADT6_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_io_sapic,f)
-#define ACPI_MADT7_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_local_sapic,f)
-#define ACPI_MADT8_OFFSET(f)            (u8) ACPI_OFFSET (struct madt_interrupt_source,f)
-#define ACPI_MADTH_OFFSET(f)            (u8) ACPI_OFFSET (struct apic_header,f)
-#define ACPI_MCFG_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_mcfg,f)
-#define ACPI_MCFG0_OFFSET(f)            (u8) ACPI_OFFSET (struct acpi_mcfg_allocation,f)
-#define ACPI_SBST_OFFSET(f)             (u8) ACPI_OFFSET (struct smart_battery_table,f)
-#define ACPI_SLIT_OFFSET(f)             (u8) ACPI_OFFSET (struct system_locality_info,f)
-#define ACPI_SPCR_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_spcr,f)
-#define ACPI_SPMI_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_spmi,f)
-#define ACPI_SRAT_OFFSET(f)             (u8) ACPI_OFFSET (struct system_resource_affinity,f)
-#define ACPI_SRAT0_OFFSET(f)            (u8) ACPI_OFFSET (struct static_resource_alloc,f)
-#define ACPI_SRAT1_OFFSET(f)            (u8) ACPI_OFFSET (struct memory_affinity,f)
-#define ACPI_TCPA_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_tcpa,f)
-#define ACPI_WDRT_OFFSET(f)             (u8) ACPI_OFFSET (struct acpi_table_wdrt,f)
-
-#define ACPI_HPET_FLAG_OFFSET(f,o)      ACPI_FLAG_OFFSET (struct hpet_table,f,o)
-#define ACPI_SRAT0_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct static_resource_alloc,f,o)
-#define ACPI_SRAT1_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct memory_affinity,f,o)
-#define ACPI_MADT_FLAG_OFFSET(f,o)      ACPI_FLAG_OFFSET (struct multiple_apic_table,f,o)
-#define ACPI_MADT0_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct madt_processor_apic,f,o)
-#define ACPI_MADT2_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct madt_interrupt_override,f,o)
-#define ACPI_MADT3_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct madt_nmi_source,f,o)
-#define ACPI_MADT4_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct madt_local_apic_nmi,f,o)
-#define ACPI_MADT7_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct madt_local_sapic,f,o)
-#define ACPI_MADT8_FLAG_OFFSET(f,o)     ACPI_FLAG_OFFSET (struct madt_interrupt_source,f,o)
+/* Flags */
+
+#define ACPI_WDRT_TIMER_ENABLED     (1)        /* 00: Timer enabled */
 
 /* Reset to default packing */
 
diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
deleted file mode 100644 (file)
index 67efe6c..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/******************************************************************************
- *
- * Name: actbl2.h - ACPI Specification Revision 2.0 Tables
- *
- *****************************************************************************/
-
-/*
- * Copyright (C) 2000 - 2006, R. Byron Moore
- * 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,
- *    without modification.
- * 2. Redistributions in binary form must reproduce at minimum a disclaimer
- *    substantially similar to the "NO WARRANTY" disclaimer below
- *    ("Disclaimer") and any redistribution must be conditioned upon
- *    including a substantially similar Disclaimer requirement for further
- *    binary redistribution.
- * 3. Neither the names of the above-listed copyright holders nor the names
- *    of any 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.
- *
- * NO WARRANTY
- * 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 MERCHANTIBILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
- */
-
-#ifndef __ACTBL2_H__
-#define __ACTBL2_H__
-
-/* Code moved to both actbl.h and actbl1.h */
-
-#endif                         /* __ACTBL2_H__ */
diff --git a/include/acpi/actbl71.h b/include/acpi/actbl71.h
deleted file mode 100644 (file)
index 10ac05b..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/******************************************************************************
- *
- * Name: actbl71.h - IA-64 Extensions to the ACPI Spec Rev. 0.71
- *                   This file includes tables specific to this
- *                   specification revision.
- *
- *****************************************************************************/
-
-/*
- *  Copyright (C) 2000 - 2003, R. Byron Moore
- *
- *  This program is free software; 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 __ACTBL71_H__
-#define __ACTBL71_H__
-
-/* 0.71 FADT address_space data item bitmasks defines */
-/* If the associated bit is zero then it is in memory space else in io space */
-
-#define SMI_CMD_ADDRESS_SPACE       0x01
-#define PM1_BLK_ADDRESS_SPACE       0x02
-#define PM2_CNT_BLK_ADDRESS_SPACE   0x04
-#define PM_TMR_BLK_ADDRESS_SPACE    0x08
-#define GPE0_BLK_ADDRESS_SPACE      0x10
-#define GPE1_BLK_ADDRESS_SPACE      0x20
-
-/* Only for clarity in declarations */
-
-typedef u64 IO_ADDRESS;
-
-#pragma pack(1)
-struct {                       /* Root System Descriptor Pointer */
-       NATIVE_CHAR signature[8];       /* contains "RSD PTR " */
-       u8 checksum;            /* to make sum of struct == 0 */
-       NATIVE_CHAR oem_id[6];  /* OEM identification */
-       u8 reserved;            /* Must be 0 for 1.0, 2 for 2.0 */
-       u64 rsdt_physical_address;      /* 64-bit physical address of RSDT */
-};
-
-/*****************************************/
-/* IA64 Extensions to ACPI Spec Rev 0.71 */
-/* for the Root System Description Table */
-/*****************************************/
-struct {
-       struct acpi_table_header header;        /* Table header */
-       u32 reserved_pad;       /* IA64 alignment, must be 0 */
-       u64 table_offset_entry[1];      /* Array of pointers to other */
-       /* tables' headers */
-};
-
-/*******************************************/
-/* IA64 Extensions to ACPI Spec Rev 0.71   */
-/* for the Firmware ACPI Control Structure */
-/*******************************************/
-struct {
-       NATIVE_CHAR signature[4];       /* signature "FACS" */
-       u32 length;             /* length of structure, in bytes */
-       u32 hardware_signature; /* hardware configuration signature */
-       u32 reserved4;          /* must be 0 */
-       u64 firmware_waking_vector;     /* ACPI OS waking vector */
-       u64 global_lock;        /* Global Lock */
-       u32 S4bios_f:1;         /* Indicates if S4BIOS support is present */
-       u32 reserved1:31;       /* must be 0 */
-       u8 reserved3[28];       /* reserved - must be zero */
-};
-
-/******************************************/
-/* IA64 Extensions to ACPI Spec Rev 0.71  */
-/* for the Fixed ACPI Description Table   */
-/******************************************/
-struct {
-       struct acpi_table_header header;        /* table header */
-       u32 reserved_pad;       /* IA64 alignment, must be 0 */
-       u64 firmware_ctrl;      /* 64-bit Physical address of FACS */
-       u64 dsdt;               /* 64-bit Physical address of DSDT */
-       u8 model;               /* System Interrupt Model */
-       u8 address_space;       /* Address Space Bitmask */
-       u16 sci_int;            /* System vector of SCI interrupt */
-       u8 acpi_enable;         /* value to write to smi_cmd to enable ACPI */
-       u8 acpi_disable;        /* value to write to smi_cmd to disable ACPI */
-       u8 S4bios_req;          /* Value to write to SMI CMD to enter S4BIOS state */
-       u8 reserved2;           /* reserved - must be zero */
-       u64 smi_cmd;            /* Port address of SMI command port */
-       u64 pm1a_evt_blk;       /* Port address of Power Mgt 1a acpi_event Reg Blk */
-       u64 pm1b_evt_blk;       /* Port address of Power Mgt 1b acpi_event Reg Blk */
-       u64 pm1a_cnt_blk;       /* Port address of Power Mgt 1a Control Reg Blk */
-       u64 pm1b_cnt_blk;       /* Port address of Power Mgt 1b Control Reg Blk */
-       u64 pm2_cnt_blk;        /* Port address of Power Mgt 2 Control Reg Blk */
-       u64 pm_tmr_blk;         /* Port address of Power Mgt Timer Ctrl Reg Blk */
-       u64 gpe0_blk;           /* Port addr of General Purpose acpi_event 0 Reg Blk */
-       u64 gpe1_blk;           /* Port addr of General Purpose acpi_event 1 Reg Blk */
-       u8 pm1_evt_len;         /* Byte length of ports at pm1_x_evt_blk */
-       u8 pm1_cnt_len;         /* Byte length of ports at pm1_x_cnt_blk */
-       u8 pm2_cnt_len;         /* Byte Length of ports at pm2_cnt_blk */
-       u8 pm_tm_len;           /* Byte Length of ports at pm_tm_blk */
-       u8 gpe0_blk_len;        /* Byte Length of ports at gpe0_blk */
-       u8 gpe1_blk_len;        /* Byte Length of ports at gpe1_blk */
-       u8 gpe1_base;           /* offset in gpe model where gpe1 events start */
-       u8 reserved3;           /* reserved */
-       u16 plvl2_lat;          /* worst case HW latency to enter/exit C2 state */
-       u16 plvl3_lat;          /* worst case HW latency to enter/exit C3 state */
-       u8 day_alrm;            /* index to day-of-month alarm in RTC CMOS RAM */
-       u8 mon_alrm;            /* index to month-of-year alarm in RTC CMOS RAM */
-       u8 century;             /* index to century in RTC CMOS RAM */
-       u8 reserved4;           /* reserved */
-       u32 flush_cash:1;       /* PAL_FLUSH_CACHE is correctly supported */
-       u32 reserved5:1;        /* reserved - must be zero */
-       u32 proc_c1:1;          /* all processors support C1 state */
-       u32 plvl2_up:1;         /* C2 state works on MP system */
-       u32 pwr_button:1;       /* Power button is handled as a generic feature */
-       u32 sleep_button:1;     /* Sleep button is handled as a generic feature, or not present */
-       u32 fixed_rTC:1;        /* RTC wakeup stat not in fixed register space */
-       u32 rtcs4:1;            /* RTC wakeup stat not possible from S4 */
-       u32 tmr_val_ext:1;      /* tmr_val is 32 bits */
-       u32 dock_cap:1;         /* Supports Docking */
-       u32 reserved6:22;       /* reserved - must be zero */
-};
-
-#pragma pack()
-
-#endif                         /* __ACTBL71_H__ */
index 64b603c..72a6e2c 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -48,7 +48,8 @@
 
 /*
  * ACPI_MACHINE_WIDTH must be specified in an OS- or compiler-dependent header
- * and must be either 16, 32, or 64
+ * and must be either 32 or 64. 16-bit ACPICA is no longer supported, as of
+ * 12/2006.
  */
 #ifndef ACPI_MACHINE_WIDTH
 #error ACPI_MACHINE_WIDTH not defined
@@ -149,7 +150,6 @@ typedef int INT32;
 typedef u64 acpi_native_uint;
 typedef s64 acpi_native_int;
 
-typedef u64 acpi_table_ptr;
 typedef u64 acpi_io_address;
 typedef u64 acpi_physical_address;
 
@@ -189,48 +189,15 @@ typedef int INT32;
 typedef u32 acpi_native_uint;
 typedef s32 acpi_native_int;
 
-typedef u64 acpi_table_ptr;
 typedef u32 acpi_io_address;
-typedef u64 acpi_physical_address;
+typedef u32 acpi_physical_address;
 
 #define ACPI_MAX_PTR                    ACPI_UINT32_MAX
 #define ACPI_SIZE_MAX                   ACPI_UINT32_MAX
 
-/*******************************************************************************
- *
- * Types specific to 16-bit targets
- *
- ******************************************************************************/
-
-#elif ACPI_MACHINE_WIDTH == 16
-
-/*! [Begin] no source code translation (keep the typedefs as-is) */
-
-typedef unsigned long UINT32;
-typedef short INT16;
-typedef long INT32;
-
-/*! [End] no source code translation !*/
-
-typedef u16 acpi_native_uint;
-typedef s16 acpi_native_int;
-
-typedef u32 acpi_table_ptr;
-typedef u32 acpi_io_address;
-typedef char *acpi_physical_address;
-
-#define ACPI_MAX_PTR                    ACPI_UINT16_MAX
-#define ACPI_SIZE_MAX                   ACPI_UINT16_MAX
-
-#define ACPI_USE_NATIVE_DIVIDE /* No 64-bit integers, ok to use native divide */
-
-/* 64-bit integers cannot be supported */
-
-#define ACPI_NO_INTEGER64_SUPPORT
-
 #else
 
-/* ACPI_MACHINE_WIDTH must be either 64, 32, or 16 */
+/* ACPI_MACHINE_WIDTH must be either 64 or 32 */
 
 #error unknown ACPI_MACHINE_WIDTH
 #endif
@@ -311,36 +278,6 @@ typedef acpi_native_uint acpi_size;
  *
  ******************************************************************************/
 
-/*
- * Pointer overlays to avoid lots of typecasting for
- * code that accepts both physical and logical pointers.
- */
-union acpi_pointers {
-       acpi_physical_address physical;
-       void *logical;
-       acpi_table_ptr value;
-};
-
-struct acpi_pointer {
-       u32 pointer_type;
-       union acpi_pointers pointer;
-};
-
-/* pointer_types for above */
-
-#define ACPI_PHYSICAL_POINTER           0x01
-#define ACPI_LOGICAL_POINTER            0x02
-
-/* Processor mode */
-
-#define ACPI_PHYSICAL_ADDRESSING        0x04
-#define ACPI_LOGICAL_ADDRESSING         0x08
-#define ACPI_MEMORY_MODE                0x0C
-
-#define ACPI_PHYSMODE_PHYSPTR           ACPI_PHYSICAL_ADDRESSING | ACPI_PHYSICAL_POINTER
-#define ACPI_LOGMODE_PHYSPTR            ACPI_LOGICAL_ADDRESSING  | ACPI_PHYSICAL_POINTER
-#define ACPI_LOGMODE_LOGPTR             ACPI_LOGICAL_ADDRESSING  | ACPI_LOGICAL_POINTER
-
 /* Logical defines and NULL */
 
 #ifdef FALSE
@@ -442,7 +379,8 @@ typedef u64 acpi_integer;
 /*
  * Initialization state
  */
-#define ACPI_INITIALIZED_OK             0x01
+#define ACPI_SUBSYSTEM_INITIALIZE       0x01
+#define ACPI_INITIALIZED_OK             0x02
 
 /*
  * Power state values
@@ -490,21 +428,6 @@ typedef u64 acpi_integer;
 #define ACPI_NOTIFY_BUS_MODE_MISMATCH   (u8) 6
 #define ACPI_NOTIFY_POWER_FAULT         (u8) 7
 
-/*
- *  Table types.  These values are passed to the table related APIs
- */
-typedef u32 acpi_table_type;
-
-#define ACPI_TABLE_ID_RSDP              (acpi_table_type) 0
-#define ACPI_TABLE_ID_DSDT              (acpi_table_type) 1
-#define ACPI_TABLE_ID_FADT              (acpi_table_type) 2
-#define ACPI_TABLE_ID_FACS              (acpi_table_type) 3
-#define ACPI_TABLE_ID_PSDT              (acpi_table_type) 4
-#define ACPI_TABLE_ID_SSDT              (acpi_table_type) 5
-#define ACPI_TABLE_ID_XSDT              (acpi_table_type) 6
-#define ACPI_TABLE_ID_MAX               6
-#define ACPI_NUM_TABLE_TYPES            (ACPI_TABLE_ID_MAX+1)
-
 /*
  * Types associated with ACPI names and objects.  The first group of
  * values (up to ACPI_TYPE_EXTERNAL_MAX) correspond to the definition
@@ -637,7 +560,7 @@ typedef u32 acpi_event_status;
  *  | | |  +--- Type of dispatch -- to method, handler, or none
  *  | | +--- Enabled for runtime?
  *  | +--- Enabled for wake?
- *  +--- System state when GPE ocurred (running/waking)
+ *  +--- Unused
  */
 #define ACPI_GPE_XRUPT_TYPE_MASK        (u8) 0x01
 #define ACPI_GPE_LEVEL_TRIGGERED        (u8) 0x01
@@ -663,10 +586,6 @@ typedef u32 acpi_event_status;
 
 #define ACPI_GPE_ENABLE_MASK            (u8) 0x60      /* Both run/wake */
 
-#define ACPI_GPE_SYSTEM_MASK            (u8) 0x80
-#define ACPI_GPE_SYSTEM_RUNNING         (u8) 0x80
-#define ACPI_GPE_SYSTEM_WAKING          (u8) 0x00
-
 /*
  * Flags for GPE and Lock interfaces
  */
@@ -815,13 +734,6 @@ struct acpi_buffer {
 #define ACPI_SYS_MODE_LEGACY            0x0002
 #define ACPI_SYS_MODES_MASK             0x0003
 
-/*
- * ACPI Table Info.  One per ACPI table _type_
- */
-struct acpi_table_info {
-       u32 count;
-};
-
 /*
  * System info returned by acpi_get_system_info()
  */
@@ -833,8 +745,6 @@ struct acpi_system_info {
        u32 reserved2;
        u32 debug_level;
        u32 debug_layer;
-       u32 num_table_types;
-       struct acpi_table_info table_info[ACPI_TABLE_ID_MAX + 1];
 };
 
 /*
index ba039ea..883ffe9 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -141,8 +141,6 @@ acpi_status acpi_ut_hardware_initialize(void);
 
 void acpi_ut_subsystem_shutdown(void);
 
-acpi_status acpi_ut_validate_fadt(void);
-
 /*
  * utclib - Local implementations of C library functions
  */
@@ -453,6 +451,8 @@ acpi_ut_short_divide(acpi_integer in_dividend,
 /*
  * utmisc
  */
+const char *acpi_ut_validate_exception(acpi_status status);
+
 u8 acpi_ut_is_aml_table(struct acpi_table_header *table);
 
 acpi_status acpi_ut_allocate_owner_id(acpi_owner_id * owner_id);
@@ -470,7 +470,7 @@ void acpi_ut_print_string(char *string, u8 max_length);
 
 u8 acpi_ut_valid_acpi_name(u32 name);
 
-acpi_name acpi_ut_repair_name(acpi_name name);
+acpi_name acpi_ut_repair_name(char *name);
 
 u8 acpi_ut_valid_acpi_char(char character, acpi_native_uint position);
 
index cf18426..da53a4e 100644 (file)
@@ -7,7 +7,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #define ARGI_DATAOBJECT             0x12       /* Buffer, String, package or reference to a Node - Used only by size_of operator */
 #define ARGI_COMPLEXOBJ             0x13       /* Buffer, String, or package (Used by INDEX op only) */
 #define ARGI_REF_OR_STRING          0x14       /* Reference or String (Used by DEREFOF op only) */
-#define ARGI_REGION_OR_FIELD        0x15       /* Used by LOAD op only */
+#define ARGI_REGION_OR_BUFFER       0x15       /* Used by LOAD op only */
 #define ARGI_DATAREFOBJ             0x16
 
 /* Note: types above can expand to 0x1F maximum */
index be03818..f7d5412 100644 (file)
@@ -6,7 +6,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 453a469..dab2ec5 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index da80933..3bb5049 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 7f1e929..5f532d2 100644 (file)
@@ -5,7 +5,7 @@
  *****************************************************************************/
 
 /*
- * Copyright (C) 2000 - 2006, R. Byron Moore
+ * Copyright (C) 2000 - 2007, R. Byron Moore
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4e115f3..85aa112 100644 (file)
@@ -293,4 +293,6 @@ struct pci_dev *alpha_gendev_to_pci(struct device *dev);
 #define IOBASE_ROOT_BUS                5
 #define IOBASE_FROM_HOSE       0x10000
 
+extern struct pci_dev *isa_bridge;
+
 #endif /* __ALPHA_PCI_H */
index 7cfad93..5e657eb 100644 (file)
@@ -39,7 +39,7 @@
  * Calling conventions:
  *
  * ACPI_SYSTEM_XFACE        - Interfaces to host OS (handlers, threads)
- * ACPI_EXTERNAL_XFACE      - External ACPI interfaces 
+ * ACPI_EXTERNAL_XFACE      - External ACPI interfaces
  * ACPI_INTERNAL_XFACE      - Internal ACPI interfaces
  * ACPI_INTERNAL_VAR_XFACE  - Internal variable-parameter list interfaces
  */
 int __acpi_acquire_global_lock(unsigned int *lock);
 int __acpi_release_global_lock(unsigned int *lock);
 
-#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
-       ((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr))
+#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
+       ((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
 
-#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
-       ((Acq) = __acpi_release_global_lock((unsigned int *) GLptr))
+#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
+       ((Acq) = __acpi_release_global_lock(&facs->global_lock))
 
 /*
  * Math helper asm macros
@@ -87,7 +87,7 @@ extern void check_acpi_pci(void);
 static inline void check_acpi_pci(void) { }
 #endif
 
-#ifdef CONFIG_ACPI 
+#ifdef CONFIG_ACPI
 extern int acpi_lapic;
 extern int acpi_ioapic;
 extern int acpi_noirq;
@@ -95,9 +95,9 @@ extern int acpi_strict;
 extern int acpi_disabled;
 extern int acpi_ht;
 extern int acpi_pci_disabled;
-static inline void disable_acpi(void) 
-{ 
-       acpi_disabled = 1; 
+static inline void disable_acpi(void)
+{
+       acpi_disabled = 1;
        acpi_ht = 0;
        acpi_pci_disabled = 1;
        acpi_noirq = 1;
@@ -114,9 +114,9 @@ extern int acpi_use_timer_override;
 #endif
 
 static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
-static inline void acpi_disable_pci(void) 
+static inline void acpi_disable_pci(void)
 {
-       acpi_pci_disabled = 1; 
+       acpi_pci_disabled = 1;
        acpi_noirq_set();
 }
 extern int acpi_irq_balance_set(char *str);
@@ -144,8 +144,6 @@ extern void acpi_reserve_bootmem(void);
 
 #endif /*CONFIG_ACPI_SLEEP*/
 
-extern u8 x86_acpiid_to_apicid[];
-
 #define ARCH_HAS_POWER_INIT    1
 
 #endif /*__KERNEL__*/
index 99f66be..24990e5 100644 (file)
@@ -3,13 +3,13 @@
 
 #include <linux/acpi.h>
 
-static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, 
+static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name,
                                struct mpc_config_translation *translation)
 {
        Dprintk("Bus #%d is %s\n", m->mpc_busid, name);
 }
 
-static inline void mpc_oem_pci_bus(struct mpc_config_bus *m, 
+static inline void mpc_oem_pci_bus(struct mpc_config_bus *m,
                                struct mpc_config_translation *translation)
 {
 }
@@ -22,7 +22,7 @@ static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
                char *productid)
 {
        if (mpc->mpc_oemptr) {
-               struct mp_config_oemtable *oem_table = 
+               struct mp_config_oemtable *oem_table =
                        (struct mp_config_oemtable *)mpc->mpc_oemptr;
                if (!strncmp(oem, "UNISYS", 6))
                        return parse_unisys_oem((char *)oem_table);
@@ -31,12 +31,13 @@ static inline int mps_oem_check(struct mp_config_table *mpc, char *oem,
 }
 
 #ifdef CONFIG_ACPI
+
 static inline int es7000_check_dsdt(void)
 {
-       struct acpi_table_header *header = NULL;
-       if(!acpi_get_table_header_early(ACPI_DSDT, &header))
-               acpi_table_print(header, 0);
-       if (!strncmp(header->oem_id, "UNISYS", 6))
+       struct acpi_table_header header;
+       memcpy(&header, 0, sizeof(struct acpi_table_header));
+       acpi_get_table_header(ACPI_SIG_DSDT, 0, &header);
+       if (!strncmp(header.oem_id, "UNISYS", 6))
                return 1;
        return 0;
 }
@@ -44,7 +45,7 @@ static inline int es7000_check_dsdt(void)
 /* Hook from generic ACPI tables.c */
 static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
-       unsigned long oem_addr; 
+       unsigned long oem_addr;
        if (!find_unisys_acpi_oem_table(&oem_addr)) {
                if (es7000_check_dsdt())
                        return parse_unisys_oem((char *)oem_addr);
index 09a5dd0..5d03792 100644 (file)
@@ -82,11 +82,11 @@ ia64_acpi_release_global_lock (unsigned int *lock)
        return old & 0x1;
 }
 
-#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq)                           \
-       ((Acq) = ia64_acpi_acquire_global_lock((unsigned int *) GLptr))
+#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq)                            \
+       ((Acq) = ia64_acpi_acquire_global_lock(&facs->global_lock))
 
-#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq)                           \
-       ((Acq) = ia64_acpi_release_global_lock((unsigned int *) GLptr))
+#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq)                            \
+       ((Acq) = ia64_acpi_release_global_lock(&facs->global_lock))
 
 #define acpi_disabled 0        /* ACPI always enabled on IA64 */
 #define acpi_noirq 0   /* ACPI always enabled on IA64 */
@@ -119,8 +119,6 @@ extern int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS];
 extern int __initdata nid_to_pxm_map[MAX_NUMNODES];
 #endif
 
-extern u16 ia64_acpiid_to_sapicid[];
-
 /*
  * Refer Intel ACPI _PDC support document for bit definitions
  */
index dad3a73..4d97f60 100644 (file)
@@ -19,4 +19,6 @@ extern unsigned long MAX_DMA_ADDRESS;
 
 #define free_dma(x)
 
+void dma_mark_clean(void *addr, size_t size);
+
 #endif /* _ASM_IA64_DMA_H */
index 84aac0e..40991c6 100644 (file)
@@ -19,7 +19,6 @@ enum esi_proc_type {
        ESI_PROC_REENTRANT      /* MP-safe and reentrant */
 };
 
-extern int ia64_esi_init (void);
 extern struct ia64_sal_retval esi_call_phys (void *, u64 *);
 extern int ia64_esi_call(efi_guid_t, struct ia64_sal_retval *,
                         enum esi_proc_type,
index a3891eb..3c96ac1 100644 (file)
@@ -21,6 +21,7 @@ struct mm_struct;
 struct pci_bus;
 struct task_struct;
 struct pci_dev;
+struct msi_desc;
 
 typedef void ia64_mv_setup_t (char **);
 typedef void ia64_mv_cpu_init_t (void);
@@ -79,7 +80,7 @@ typedef unsigned short ia64_mv_readw_relaxed_t (const volatile void __iomem *);
 typedef unsigned int ia64_mv_readl_relaxed_t (const volatile void __iomem *);
 typedef unsigned long ia64_mv_readq_relaxed_t (const volatile void __iomem *);
 
-typedef int ia64_mv_setup_msi_irq_t (unsigned int irq, struct pci_dev *pdev);
+typedef int ia64_mv_setup_msi_irq_t (struct pci_dev *pdev, struct msi_desc *);
 typedef void ia64_mv_teardown_msi_irq_t (unsigned int irq);
 
 static inline void
index c8df759..6dd476b 100644 (file)
@@ -51,12 +51,13 @@ extern void efi_memmap_init(unsigned long *, unsigned long *);
 
 #define IGNORE_PFN0    1       /* XXX fix me: ignore pfn 0 until TLB miss handler is updated... */
 
+extern int register_active_ranges(u64 start, u64 end, void *arg);
+
 #ifdef CONFIG_VIRTUAL_MEM_MAP
 # define LARGE_GAP     0x40000000 /* Use virtual mem map if hole is > than this */
   extern unsigned long vmalloc_end;
   extern struct page *vmem_map;
   extern int find_largest_hole (u64 start, u64 end, void *arg);
-  extern int register_active_ranges (u64 start, u64 end, void *arg);
   extern int create_mem_map_page_table (u64 start, u64 end, void *arg);
   extern int vmemmap_find_next_valid_pfn(int, int);
 #else
index 393e04c..560c287 100644 (file)
@@ -137,7 +137,8 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t * pmd_entry, pte_t * pte)
 static inline struct page *pte_alloc_one(struct mm_struct *mm,
                                         unsigned long addr)
 {
-       return virt_to_page(pgtable_quicklist_alloc());
+       void *pg = pgtable_quicklist_alloc();
+       return pg ? virt_to_page(pg) : NULL;
 }
 
 static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
index 2850a7e..9ce2801 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "acpi/acglobal.h"
 
-#define SN_ACPI_BASE_SUPPORT()   (acpi_gbl_DSDT->oem_revision >= 0x20101)
+extern int sn_acpi_rev;
+#define SN_ACPI_BASE_SUPPORT()   (sn_acpi_rev >= 0x20101)
 
 #endif /* _ASM_IA64_SN_ACPI_H */
index da3eade..17cb6cc 100644 (file)
@@ -142,7 +142,7 @@ extern int          pcibr_ate_alloc(struct pcibus_info *, int);
 extern void            pcibr_ate_free(struct pcibus_info *, int);
 extern void            ate_write(struct pcibus_info *, int, int, u64);
 extern int sal_pcibr_slot_enable(struct pcibus_info *soft, int device,
-                                void *resp);
+                                void *resp, char **ssdt);
 extern int sal_pcibr_slot_disable(struct pcibus_info *soft, int device,
                                  int action, void *resp);
 extern u16 sn_ioboard_to_pci_bus(struct pci_bus *pci_bus);
index 9fe89a9..1c2382c 100644 (file)
@@ -70,10 +70,16 @@ extern void sn_irq_fixup(struct pci_dev *pci_dev,
                         struct sn_irq_info *sn_irq_info);
 extern void sn_irq_unfixup(struct pci_dev *pci_dev);
 extern struct pcidev_info * sn_pcidev_info_get(struct pci_dev *);
+extern void sn_bus_fixup(struct pci_bus *);
+extern void sn_acpi_bus_fixup(struct pci_bus *);
+extern void sn_common_bus_fixup(struct pci_bus *, struct pcibus_bussoft *);
 extern void sn_bus_store_sysdata(struct pci_dev *dev);
 extern void sn_bus_free_sysdata(void);
 extern void sn_generate_path(struct pci_bus *pci_bus, char *address);
-extern void sn_pci_fixup_slot(struct pci_dev *dev);
+extern void sn_io_slot_fixup(struct pci_dev *);
+extern void sn_acpi_slot_fixup(struct pci_dev *);
+extern void sn_pci_fixup_slot(struct pci_dev *dev, struct pcidev_info *,
+                             struct sn_irq_info *);
 extern void sn_pci_unfixup_slot(struct pci_dev *dev);
 extern void sn_irq_lh_init(void);
 #endif                         /* _ASM_IA64_SN_PCI_PCIDEV_H */
diff --git a/include/asm-ia64/swiotlb.h b/include/asm-ia64/swiotlb.h
new file mode 100644 (file)
index 0000000..452c162
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _ASM_SWIOTLB_H
+#define _ASM_SWIOTLB_H 1
+
+#include <asm/machvec.h>
+
+#define SWIOTLB_ARCH_NEED_LATE_INIT
+#define SWIOTLB_ARCH_NEED_ALLOC
+
+#endif /* _ASM_SWIOTLB_H */
index 9b505b2..9169859 100644 (file)
@@ -84,6 +84,7 @@ struct thread_info {
 #define TIF_NEED_RESCHED       2       /* rescheduling necessary */
 #define TIF_SYSCALL_TRACE      3       /* syscall trace active */
 #define TIF_SYSCALL_AUDIT      4       /* syscall auditing active */
+#define TIF_SINGLESTEP         5       /* restore singlestep on return to user mode */
 #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 */
@@ -92,7 +93,8 @@ struct thread_info {
 
 #define _TIF_SYSCALL_TRACE     (1 << TIF_SYSCALL_TRACE)
 #define _TIF_SYSCALL_AUDIT     (1 << TIF_SYSCALL_AUDIT)
-#define _TIF_SYSCALL_TRACEAUDIT        (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT)
+#define _TIF_SINGLESTEP                (1 << TIF_SINGLESTEP)
+#define _TIF_SYSCALL_TRACEAUDIT        (_TIF_SYSCALL_TRACE|_TIF_SYSCALL_AUDIT|_TIF_SINGLESTEP)
 #define _TIF_NOTIFY_RESUME     (1 << TIF_NOTIFY_RESUME)
 #define _TIF_SIGPENDING                (1 << TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1 << TIF_NEED_RESCHED)
index 53c5c0e..a9e1fa4 100644 (file)
 #define __NR_sync_file_range           1300
 #define __NR_tee                       1301
 #define __NR_vmsplice                  1302
+/* 1303 reserved for move_pages */
+#define __NR_getcpu                    1304
 
 #ifdef __KERNEL__
 
 
-#define NR_syscalls                    279 /* length of syscall table */
+#define NR_syscalls                    281 /* length of syscall table */
 
 #define __ARCH_WANT_SYS_RT_SIGACTION
 
index 8e321f5..c7c945b 100644 (file)
@@ -243,6 +243,10 @@ extern struct boot_mem_map boot_mem_map;
 extern void add_memory_region(phys_t start, phys_t size, long type);
 
 extern void prom_init(void);
+extern void prom_free_prom_memory(void);
+
+extern void free_init_pages(const char *what,
+                           unsigned long begin, unsigned long end);
 
 /*
  * Initial kernel command line, usually setup by prom_init()
index c5af4b7..6cf177c 100644 (file)
@@ -17,6 +17,7 @@
 #ifndef __ASM_DDB5XXX_DDB5477_H
 #define __ASM_DDB5XXX_DDB5477_H
 
+#include <irq.h>
 
 /*
  * This contains macros that are specific to DDB5477 or renamed from
@@ -251,14 +252,10 @@ extern void ll_vrc5477_irq_disable(int vrc5477_irq);
  */
 
 #define        NUM_CPU_IRQ             8
-#define        NUM_I8259_IRQ           16
 #define        NUM_VRC5477_IRQ         32
 
-#define        DDB_IRQ_BASE            0
-
-#define        I8259_IRQ_BASE          DDB_IRQ_BASE
-#define        VRC5477_IRQ_BASE        (I8259_IRQ_BASE + NUM_I8259_IRQ)
-#define        CPU_IRQ_BASE            (VRC5477_IRQ_BASE + NUM_VRC5477_IRQ)
+#define        CPU_IRQ_BASE            MIPS_CPU_IRQ_BASE
+#define        VRC5477_IRQ_BASE        (CPU_IRQ_BASE + NUM_CPU_IRQ)
 
 /*
  * vrc5477 irq defs
@@ -300,22 +297,22 @@ extern void ll_vrc5477_irq_disable(int vrc5477_irq);
 /*
  * i2859 irq assignment
  */
-#define I8259_IRQ_RESERVED_0   (0 + I8259_IRQ_BASE)
-#define I8259_IRQ_KEYBOARD     (1 + I8259_IRQ_BASE)    /* M1543 default */
-#define I8259_IRQ_CASCADE      (2 + I8259_IRQ_BASE)
-#define I8259_IRQ_UART_B       (3 + I8259_IRQ_BASE)    /* M1543 default, may conflict with RTC according to schematic diagram  */
-#define I8259_IRQ_UART_A       (4 + I8259_IRQ_BASE)    /* M1543 default */
-#define I8259_IRQ_PARALLEL     (5 + I8259_IRQ_BASE)    /* M1543 default */
-#define I8259_IRQ_RESERVED_6   (6 + I8259_IRQ_BASE)
-#define I8259_IRQ_RESERVED_7   (7 + I8259_IRQ_BASE)
-#define I8259_IRQ_RTC          (8 + I8259_IRQ_BASE)    /* who set this? */
-#define I8259_IRQ_USB          (9 + I8259_IRQ_BASE)    /* ddb_setup */
-#define I8259_IRQ_PMU          (10 + I8259_IRQ_BASE)   /* ddb_setup */
-#define I8259_IRQ_RESERVED_11  (11 + I8259_IRQ_BASE)
-#define I8259_IRQ_RESERVED_12  (12 + I8259_IRQ_BASE)   /* m1543_irq_setup */
-#define I8259_IRQ_RESERVED_13  (13 + I8259_IRQ_BASE)
-#define I8259_IRQ_HDC1         (14 + I8259_IRQ_BASE)   /* default and ddb_setup */
-#define I8259_IRQ_HDC2         (15 + I8259_IRQ_BASE)   /* default */
+#define I8259_IRQ_RESERVED_0   (0 + I8259A_IRQ_BASE)
+#define I8259_IRQ_KEYBOARD     (1 + I8259A_IRQ_BASE)   /* M1543 default */
+#define I8259_IRQ_CASCADE      (2 + I8259A_IRQ_BASE)
+#define I8259_IRQ_UART_B       (3 + I8259A_IRQ_BASE)   /* M1543 default, may conflict with RTC according to schematic diagram  */
+#define I8259_IRQ_UART_A       (4 + I8259A_IRQ_BASE)   /* M1543 default */
+#define I8259_IRQ_PARALLEL     (5 + I8259A_IRQ_BASE)   /* M1543 default */
+#define I8259_IRQ_RESERVED_6   (6 + I8259A_IRQ_BASE)
+#define I8259_IRQ_RESERVED_7   (7 + I8259A_IRQ_BASE)
+#define I8259_IRQ_RTC          (8 + I8259A_IRQ_BASE)   /* who set this? */
+#define I8259_IRQ_USB          (9 + I8259A_IRQ_BASE)   /* ddb_setup */
+#define I8259_IRQ_PMU          (10 + I8259A_IRQ_BASE)  /* ddb_setup */
+#define I8259_IRQ_RESERVED_11  (11 + I8259A_IRQ_BASE)
+#define I8259_IRQ_RESERVED_12  (12 + I8259A_IRQ_BASE)  /* m1543_irq_setup */
+#define I8259_IRQ_RESERVED_13  (13 + I8259A_IRQ_BASE)
+#define I8259_IRQ_HDC1         (14 + I8259A_IRQ_BASE)  /* default and ddb_setup */
+#define I8259_IRQ_HDC2         (15 + I8259A_IRQ_BASE)  /* default */
 
 
 /*
index 273e4d6..e10d341 100644 (file)
@@ -14,6 +14,7 @@
 #ifndef __ASM_DEC_INTERRUPTS_H
 #define __ASM_DEC_INTERRUPTS_H
 
+#include <irq.h>
 #include <asm/mipsregs.h>
 
 
@@ -87,7 +88,7 @@
 #define DEC_CPU_INR_SW1                1       /* software #1 */
 #define DEC_CPU_INR_SW0                0       /* software #0 */
 
-#define DEC_CPU_IRQ_BASE       0       /* first IRQ assigned to CPU */
+#define DEC_CPU_IRQ_BASE       MIPS_CPU_IRQ_BASE       /* first IRQ assigned to CPU */
 
 #define DEC_CPU_IRQ_NR(n)      ((n) + DEC_CPU_IRQ_BASE)
 #define DEC_CPU_IRQ_MASK(n)    (1 << ((n) + CAUSEB_IP))
index 23f789c..e06ef07 100644 (file)
@@ -91,6 +91,7 @@
 #else
 #define MAX_DMA_ADDRESS                (PAGE_OFFSET + 0x01000000)
 #endif
+#define MAX_DMA_PFN            PFN_DOWN(virt_to_phys((void *)MAX_DMA_ADDRESS))
 
 /* 8237 DMA controllers */
 #define IO_DMA1_BASE   0x00    /* 8 bit slave DMA, channels 0..3 */
index 4fb8df7..6a1af0a 100644 (file)
@@ -24,6 +24,8 @@
 #ifndef __ASM_EMMA2RH_EMMA2RH_H
 #define __ASM_EMMA2RH_EMMA2RH_H
 
+#include <irq.h>
+
 /*
  * EMMA2RH registers
  */
 #define NUM_EMMA2RH_IRQ                96
 
 #define CPU_EMMA2RH_CASCADE    2
-#define EMMA2RH_IRQ_BASE       0
+#define CPU_IRQ_BASE           MIPS_CPU_IRQ_BASE
+#define EMMA2RH_IRQ_BASE       (CPU_IRQ_BASE + NUM_CPU_IRQ)
 
 /*
  * emma2rh irq defs
index 8fa7667..973b062 100644 (file)
@@ -33,7 +33,6 @@
 
 #define EMMA2RH_SW_IRQ_BASE    (EMMA2RH_IRQ_BASE + NUM_EMMA2RH_IRQ)
 #define EMMA2RH_GPIO_IRQ_BASE  (EMMA2RH_SW_IRQ_BASE + NUM_EMMA2RH_IRQ_SW)
-#define CPU_IRQ_BASE           (EMMA2RH_GPIO_IRQ_BASE + NUM_EMMA2RH_IRQ_GPIO)
 
 #define EMMA2RH_SW_IRQ_INT0    (0+EMMA2RH_SW_IRQ_BASE)
 #define EMMA2RH_SW_IRQ_INT1    (1+EMMA2RH_SW_IRQ_BASE)
index 4df8d8b..e88a016 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/spinlock.h>
 
 #include <asm/io.h>
+#include <irq.h>
 
 /* i8259A PIC registers */
 #define PIC_MASTER_CMD         0x20
@@ -42,8 +43,6 @@ extern void disable_8259A_irq(unsigned int irq);
 
 extern void init_i8259_irqs(void);
 
-#define I8259A_IRQ_BASE        0
-
 /*
  * Do the traditional i8259 interrupt polling thing.  This is for the few
  * cases where no better interrupt acknowledge method is available and we
index d77b657..67f0810 100644 (file)
@@ -115,7 +115,7 @@ static inline void set_io_port_base(unsigned long base)
  */
 static inline unsigned long virt_to_phys(volatile const void *address)
 {
-       return (unsigned long)address - PAGE_OFFSET;
+       return (unsigned long)address - PAGE_OFFSET + PHYS_OFFSET;
 }
 
 /*
@@ -132,7 +132,7 @@ static inline unsigned long virt_to_phys(volatile const void *address)
  */
 static inline void * phys_to_virt(unsigned long address)
 {
-       return (void *)(address + PAGE_OFFSET);
+       return (void *)(address + PAGE_OFFSET - PHYS_OFFSET);
 }
 
 /*
index 386da82..91803ba 100644 (file)
@@ -18,7 +18,7 @@
 #ifdef CONFIG_I8259
 static inline int irq_canonicalize(int irq)
 {
-       return ((irq == 2) ? 9 : irq);
+       return ((irq == I8259A_IRQ_BASE + 2) ? I8259A_IRQ_BASE + 9 : irq);
 }
 #else
 #define irq_canonicalize(irq) (irq)    /* Sane hardware, sane code ... */
index ed3d1e3..ef6a07c 100644 (file)
@@ -13,8 +13,8 @@
 #ifndef _ASM_IRQ_CPU_H
 #define _ASM_IRQ_CPU_H
 
-extern void mips_cpu_irq_init(int irq_base);
-extern void rm7k_cpu_irq_init(int irq_base);
-extern void rm9k_cpu_irq_init(int irq_base);
+extern void mips_cpu_irq_init(void);
+extern void rm7k_cpu_irq_init(void);
+extern void rm9k_cpu_irq_init(void);
 
 #endif /* _ASM_IRQ_CPU_H */
index 582acd8..58fca8a 100644 (file)
@@ -39,6 +39,7 @@
 #ifndef _LANGUAGE_ASSEMBLY
 
 #include <linux/delay.h>
+#include <linux/types.h>
 #include <asm/io.h>
 
 /* cpu pipeline flush */
index 00b0fc6..24a8d51 100644 (file)
@@ -12,6 +12,8 @@
 #ifndef __ASM_COBALT_H
 #define __ASM_COBALT_H
 
+#include <irq.h>
+
 /*
  * i8259 legacy interrupts used on Cobalt:
  *
@@ -25,7 +27,7 @@
 /*
  * CPU IRQs  are 16 ... 23
  */
-#define COBALT_CPU_IRQ         16
+#define COBALT_CPU_IRQ         MIPS_CPU_IRQ_BASE
 
 #define COBALT_GALILEO_IRQ     (COBALT_CPU_IRQ + 2)
 #define COBALT_SCC_IRQ          (COBALT_CPU_IRQ + 3)   /* pre-production has 85C30 */
index bce6424..5439eb8 100644 (file)
@@ -10,4 +10,6 @@
 
 #define NR_IRQS        256
 
+#include_next <irq.h>
+
 #endif /* __ASM_MACH_EMMA2RH_IRQ_H */
index 500e10f..70d9a25 100644 (file)
@@ -8,6 +8,38 @@
 #ifndef __ASM_MACH_GENERIC_IRQ_H
 #define __ASM_MACH_GENERIC_IRQ_H
 
+#ifndef NR_IRQS
 #define NR_IRQS        128
+#endif
+
+#ifdef CONFIG_I8259
+#ifndef I8259A_IRQ_BASE
+#define I8259A_IRQ_BASE        0
+#endif
+#endif
+
+#ifdef CONFIG_IRQ_CPU
+
+#ifndef MIPS_CPU_IRQ_BASE
+#ifdef CONFIG_I8259
+#define MIPS_CPU_IRQ_BASE 16
+#else
+#define MIPS_CPU_IRQ_BASE 0
+#endif /* CONFIG_I8259 */
+#endif
+
+#ifdef CONFIG_IRQ_CPU_RM7K
+#ifndef RM7K_CPU_IRQ_BASE
+#define RM7K_CPU_IRQ_BASE (MIPS_CPU_IRQ_BASE+8)
+#endif
+#endif
+
+#ifdef CONFIG_IRQ_CPU_RM9K
+#ifndef RM9K_CPU_IRQ_BASE
+#define RM9K_CPU_IRQ_BASE (MIPS_CPU_IRQ_BASE+12)
+#endif
+#endif
+
+#endif /* CONFIG_IRQ_CPU */
 
 #endif /* __ASM_MACH_GENERIC_IRQ_H */
index e994b0c..9b9da26 100644 (file)
@@ -4,4 +4,6 @@
 
 #define NR_IRQS        256
 
+#include_next <irq.h>
+
 #endif /* __ASM_MACH_MIPS_IRQ_H */
diff --git a/include/asm-mips/mach-vr41xx/irq.h b/include/asm-mips/mach-vr41xx/irq.h
new file mode 100644 (file)
index 0000000..8488122
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __ASM_MACH_VR41XX_IRQ_H
+#define __ASM_MACH_VR41XX_IRQ_H
+
+#include <asm/vr41xx/irq.h> /* for MIPS_CPU_IRQ_BASE */
+#ifdef CONFIG_NEC_CMBVR4133
+#include <asm/vr41xx/cmbvr4133.h> /* for I8259A_IRQ_BASE */
+#endif
+
+#include_next <irq.h>
+
+#endif /* __ASM_MACH_VR41XX_IRQ_H */
index b15e4ea..76add42 100644 (file)
 #ifndef _MIPS_ATLASINT_H
 #define _MIPS_ATLASINT_H
 
+#include <irq.h>
+
 /*
  * Interrupts 0..7 are used for Atlas CPU interrupts (nonEIC mode)
  */
-#define MIPSCPU_INT_BASE       0
+#define MIPSCPU_INT_BASE       MIPS_CPU_IRQ_BASE
 
 /* CPU interrupt offsets */
 #define MIPSCPU_INT_SW0                0
index da6cc2f..9180d64 100644 (file)
@@ -25,6 +25,8 @@
 #ifndef _MIPS_MALTAINT_H
 #define _MIPS_MALTAINT_H
 
+#include <irq.h>
+
 /*
  * Interrupts 0..15 are used for Malta ISA compatible interrupts
  */
@@ -33,7 +35,7 @@
 /*
  * Interrupts 16..23 are used for Malta CPU interrupts (nonEIC mode)
  */
-#define MIPSCPU_INT_BASE       16
+#define MIPSCPU_INT_BASE       MIPS_CPU_IRQ_BASE
 
 /* CPU interrupt offsets */
 #define MIPSCPU_INT_SW0                0
index 4168c7f..7bf6f5f 100644 (file)
@@ -33,7 +33,6 @@ extern void prom_printf(char *fmt, ...);
 extern void prom_init_cmdline(void);
 extern void prom_meminit(void);
 extern void prom_fixup_mem_map(unsigned long start_mem, unsigned long end_mem);
-extern unsigned long prom_free_prom_memory (void);
 extern void mips_display_message(const char *str);
 extern void mips_display_word(unsigned int num);
 extern int get_ethernet_addr(char *ethernet_addr);
index 365c2a3..4f6a393 100644 (file)
 #ifndef _MIPS_SEADINT_H
 #define _MIPS_SEADINT_H
 
+#include <irq.h>
+
 /*
  * Interrupts 0..7 are used for SEAD CPU interrupts
  */
-#define MIPSCPU_INT_BASE       0
+#define MIPSCPU_INT_BASE       MIPS_CPU_IRQ_BASE
 
 #define MIPSCPU_INT_UART0      2
 #define MIPSCPU_INT_UART1      3
index 4952e0b..54f2fe6 100644 (file)
 #ifndef _MIPS_SIMINT_H
 #define _MIPS_SIMINT_H
 
+#include <irq.h>
 
 #define SIM_INT_BASE           0
 #define MIPSCPU_INT_MB0                2
-#define MIPSCPU_INT_BASE       16
+#define MIPSCPU_INT_BASE       MIPS_CPU_IRQ_BASE
 #define MIPS_CPU_TIMER_IRQ     7
 
 
index 3e9468f..294bca1 100644 (file)
 
 #ifndef __ASSEMBLY__
 
-extern void mips_mt_regdump(unsigned long previous_mvpcontrol_value);
-
 static inline unsigned int dvpe(void)
 {
        int res = 0;
index 2f9e1a9..d3fbd83 100644 (file)
 
 #ifndef __ASSEMBLY__
 
+/*
+ * This gives the physical RAM offset.
+ */
+#ifndef PHYS_OFFSET
+#define PHYS_OFFSET            0UL
+#endif
+
+/*
+ * It's normally defined only for FLATMEM config but it's
+ * used in our early mem init code for all memory models.
+ * So always define it.
+ */
+#define ARCH_PFN_OFFSET                PFN_UP(PHYS_OFFSET)
+
 #include <linux/pfn.h>
 #include <asm/io.h>
 
@@ -132,20 +146,23 @@ typedef struct { unsigned long pgprot; } pgprot_t;
 /* to align the pointer to the (next) page boundary */
 #define PAGE_ALIGN(addr)       (((addr) + PAGE_SIZE - 1) & PAGE_MASK)
 
+/*
+ * __pa()/__va() should be used only during mem init.
+ */
 #if defined(CONFIG_64BIT) && !defined(CONFIG_BUILD_ELF64)
 #define __pa_page_offset(x)    ((unsigned long)(x) < CKSEG0 ? PAGE_OFFSET : CKSEG0)
 #else
 #define __pa_page_offset(x)    PAGE_OFFSET
 #endif
-#define __pa(x)                        ((unsigned long)(x) - __pa_page_offset(x))
-#define __pa_symbol(x)         __pa(RELOC_HIDE((unsigned long)(x),0))
-#define __va(x)                        ((void *)((unsigned long)(x) + PAGE_OFFSET))
+#define __pa(x)                ((unsigned long)(x) - __pa_page_offset(x) + PHYS_OFFSET)
+#define __va(x)                ((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
+#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x),0))
 
 #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
 
 #ifdef CONFIG_FLATMEM
 
-#define pfn_valid(pfn)         ((pfn) < max_mapnr)
+#define pfn_valid(pfn)         ((pfn) >= ARCH_PFN_OFFSET && (pfn) < max_mapnr)
 
 #elif defined(CONFIG_SPARSEMEM)
 
index 76cd51c..59162f7 100644 (file)
@@ -6,9 +6,10 @@
 #ifndef __ASM_RTLX_H
 #define __ASM_RTLX_H_
 
+#include <irq.h>
+
 #define LX_NODE_BASE 10
 
-#define MIPSCPU_INT_BASE       16
 #define MIPS_CPU_RTLX_IRQ 0
 
 #define RTLX_VERSION 2
index f701627..b7e3726 100644 (file)
@@ -3,6 +3,4 @@
 
 #include <asm-generic/sections.h>
 
-extern char _fdata;
-
 #endif /* _ASM_SECTIONS_H */
index bbfc05c..6592f3b 100644 (file)
  * HAL2 driver). This will prevent many complications, trust me ;-)
  */
 
+#include <irq.h>
 #include <asm/sgi/ioc.h>
 
 #define SGINT_EISA     0       /* 16 EISA irq levels (Indigo2) */
-#define SGINT_CPU      16      /* MIPS CPU define 8 interrupt sources */
-#define SGINT_LOCAL0   24      /* 8 local0 irq levels */
-#define SGINT_LOCAL1   32      /* 8 local1 irq levels */
-#define SGINT_LOCAL2   40      /* 8 local2 vectored irq levels */
-#define SGINT_LOCAL3   48      /* 8 local3 vectored irq levels */
-#define SGINT_END      56      /* End of 'spaces' */
+#define SGINT_CPU      MIPS_CPU_IRQ_BASE       /* MIPS CPU define 8 interrupt sources */
+#define SGINT_LOCAL0   (SGINT_CPU+8)   /* 8 local0 irq levels */
+#define SGINT_LOCAL1   (SGINT_CPU+16)  /* 8 local1 irq levels */
+#define SGINT_LOCAL2   (SGINT_CPU+24)  /* 8 local2 vectored irq levels */
+#define SGINT_LOCAL3   (SGINT_CPU+32)  /* 8 local3 vectored irq levels */
+#define SGINT_END      (SGINT_CPU+40)  /* End of 'spaces' */
 
 /*
  * Individual interrupt definitions for the Indy and Indigo2
index f22c3e2..55f3419 100644 (file)
@@ -44,9 +44,6 @@ struct smtc_ipi_q {
        int depth;
 };
 
-extern struct smtc_ipi_q IPIQ[NR_CPUS];
-extern struct smtc_ipi_q freeIPIq;
-
 static inline void smtc_ipi_nq(struct smtc_ipi_q *q, struct smtc_ipi *p)
 {
        long flags;
index 1cdd4ee..c12ebc5 100644 (file)
@@ -488,7 +488,8 @@ extern size_t __copy_user(void *__to, const void *__from, size_t __n);
 })
 
 /*
- * __copy_from_user: - Copy a block of data from user space, with less checking. * @to:   Destination address, in kernel space.
+ * __copy_from_user: - Copy a block of data from user space, with less checking.
+ * @to:   Destination address, in kernel space.
  * @from: Source address, in user space.
  * @n:    Number of bytes to copy.
  *
index 9490ade..4230003 100644 (file)
@@ -35,8 +35,8 @@
 #define CMBVR41XX_INTD_IRQ             GIU_IRQ(CMBVR41XX_INTD_PIN)
 #define CMBVR41XX_INTE_IRQ             GIU_IRQ(CMBVR41XX_INTE_PIN)
 
-#define I8259_IRQ_BASE                 72
-#define I8259_IRQ(x)                   (I8259_IRQ_BASE + (x))
+#define I8259A_IRQ_BASE                        72
+#define I8259_IRQ(x)                   (I8259A_IRQ_BASE + (x))
 #define TIMER_IRQ                      I8259_IRQ(0)
 #define KEYBOARD_IRQ                   I8259_IRQ(1)
 #define I8259_SLAVE_IRQ                        I8259_IRQ(2)
@@ -52,6 +52,5 @@
 #define AUX_IRQ                                I8259_IRQ(12)
 #define IDE_PRIMARY_IRQ                        I8259_IRQ(14)
 #define IDE_SECONDARY_IRQ              I8259_IRQ(15)
-#define I8259_IRQ_LAST                 IDE_SECONDARY_IRQ
 
 #endif /* __NEC_CMBVR4133_H */
index 356a0b1..296f4f1 100644 (file)
@@ -6,6 +6,34 @@
 #include <linux/types.h>
 #include <linux/sched.h>
 
+#define PSW32_MASK_PER         0x40000000UL
+#define PSW32_MASK_DAT         0x04000000UL
+#define PSW32_MASK_IO          0x02000000UL
+#define PSW32_MASK_EXT         0x01000000UL
+#define PSW32_MASK_KEY         0x00F00000UL
+#define PSW32_MASK_MCHECK      0x00040000UL
+#define PSW32_MASK_WAIT                0x00020000UL
+#define PSW32_MASK_PSTATE      0x00010000UL
+#define PSW32_MASK_ASC         0x0000C000UL
+#define PSW32_MASK_CC          0x00003000UL
+#define PSW32_MASK_PM          0x00000f00UL
+
+#define PSW32_ADDR_AMODE31     0x80000000UL
+#define PSW32_ADDR_INSN                0x7FFFFFFFUL
+
+#define PSW32_BASE_BITS                0x00080000UL
+
+#define PSW32_ASC_PRIMARY      0x00000000UL
+#define PSW32_ASC_ACCREG       0x00004000UL
+#define PSW32_ASC_SECONDARY    0x00008000UL
+#define PSW32_ASC_HOME         0x0000C000UL
+
+#define PSW32_MASK_MERGE(CURRENT,NEW) \
+       (((CURRENT) & ~(PSW32_MASK_CC|PSW32_MASK_PM)) | \
+        ((NEW) & (PSW32_MASK_CC|PSW32_MASK_PM)))
+
+extern long psw32_user_bits;
+
 #define COMPAT_USER_HZ 100
 
 typedef u32            compat_size_t;
diff --git a/include/asm-s390/etr.h b/include/asm-s390/etr.h
new file mode 100644 (file)
index 0000000..b498f19
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ *  include/asm-s390/etr.h
+ *
+ *  Copyright IBM Corp. 2006
+ *  Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
+ */
+#ifndef __S390_ETR_H
+#define __S390_ETR_H
+
+/* ETR attachment control register */
+struct etr_eacr {
+       unsigned int e0         : 1;    /* port 0 stepping control */
+       unsigned int e1         : 1;    /* port 1 stepping control */
+       unsigned int _pad0      : 5;    /* must be 00100 */
+       unsigned int dp         : 1;    /* data port control */
+       unsigned int p0         : 1;    /* port 0 change recognition control */
+       unsigned int p1         : 1;    /* port 1 change recognition control */
+       unsigned int _pad1      : 3;    /* must be 000 */
+       unsigned int ea         : 1;    /* ETR alert control */
+       unsigned int es         : 1;    /* ETR sync check control */
+       unsigned int sl         : 1;    /* switch to local control */
+} __attribute__ ((packed));
+
+/* Port state returned by steai */
+enum etr_psc {
+       etr_psc_operational = 0,
+       etr_psc_semi_operational = 1,
+       etr_psc_protocol_error =  4,
+       etr_psc_no_symbols = 8,
+       etr_psc_no_signal = 12,
+       etr_psc_pps_mode = 13
+};
+
+/* Logical port state returned by stetr */
+enum etr_lpsc {
+       etr_lpsc_operational_step = 0,
+       etr_lpsc_operational_alt = 1,
+       etr_lpsc_semi_operational = 2,
+       etr_lpsc_protocol_error =  4,
+       etr_lpsc_no_symbol_sync = 8,
+       etr_lpsc_no_signal = 12,
+       etr_lpsc_pps_mode = 13
+};
+
+/* ETR status words */
+struct etr_esw {
+       struct etr_eacr eacr;           /* attachment control register */
+       unsigned int y          : 1;    /* stepping mode */
+       unsigned int _pad0      : 5;    /* must be 00000 */
+       unsigned int p          : 1;    /* stepping port number */
+       unsigned int q          : 1;    /* data port number */
+       unsigned int psc0       : 4;    /* port 0 state code */
+       unsigned int psc1       : 4;    /* port 1 state code */
+} __attribute__ ((packed));
+
+/* Second level data register status word */
+struct etr_slsw {
+       unsigned int vv1        : 1;    /* copy of validity bit data frame 1 */
+       unsigned int vv2        : 1;    /* copy of validity bit data frame 2 */
+       unsigned int vv3        : 1;    /* copy of validity bit data frame 3 */
+       unsigned int vv4        : 1;    /* copy of validity bit data frame 4 */
+       unsigned int _pad0      : 19;   /* must by all zeroes */
+       unsigned int n          : 1;    /* EAF port number */
+       unsigned int v1         : 1;    /* validity bit ETR data frame 1 */
+       unsigned int v2         : 1;    /* validity bit ETR data frame 2 */
+       unsigned int v3         : 1;    /* validity bit ETR data frame 3 */
+       unsigned int v4         : 1;    /* validity bit ETR data frame 4 */
+       unsigned int _pad1      : 4;    /* must be 0000 */
+} __attribute__ ((packed));
+
+/* ETR data frames */
+struct etr_edf1 {
+       unsigned int u          : 1;    /* untuned bit */
+       unsigned int _pad0      : 1;    /* must be 0 */
+       unsigned int r          : 1;    /* service request bit */
+       unsigned int _pad1      : 4;    /* must be 0000 */
+       unsigned int a          : 1;    /* time adjustment bit */
+       unsigned int net_id     : 8;    /* ETR network id */
+       unsigned int etr_id     : 8;    /* id of ETR which sends data frames */
+       unsigned int etr_pn     : 8;    /* port number of ETR output port */
+} __attribute__ ((packed));
+
+struct etr_edf2 {
+       unsigned int etv        : 32;   /* Upper 32 bits of TOD. */
+} __attribute__ ((packed));
+
+struct etr_edf3 {
+       unsigned int rc         : 8;    /* failure reason code */
+       unsigned int _pad0      : 3;    /* must be 000 */
+       unsigned int c          : 1;    /* ETR coupled bit */
+       unsigned int tc         : 4;    /* ETR type code */
+       unsigned int blto       : 8;    /* biased local time offset */
+                                       /* (blto - 128) * 15 = minutes */
+       unsigned int buo        : 8;    /* biased utc offset */
+                                       /* (buo - 128) = leap seconds */
+} __attribute__ ((packed));
+
+struct etr_edf4 {
+       unsigned int ed         : 8;    /* ETS device dependent data */
+       unsigned int _pad0      : 1;    /* must be 0 */
+       unsigned int buc        : 5;    /* biased ut1 correction */
+                                       /* (buc - 16) * 0.1 seconds */
+       unsigned int em         : 6;    /* ETS error magnitude */
+       unsigned int dc         : 6;    /* ETS drift code */
+       unsigned int sc         : 6;    /* ETS steering code */
+} __attribute__ ((packed));
+
+/*
+ * ETR attachment information block, two formats
+ * format 1 has 4 reserved words with a size of 64 bytes
+ * format 2 has 16 reserved words with a size of 96 bytes
+ */
+struct etr_aib {
+       struct etr_esw esw;
+       struct etr_slsw slsw;
+       unsigned long long tsp;
+       struct etr_edf1 edf1;
+       struct etr_edf2 edf2;
+       struct etr_edf3 edf3;
+       struct etr_edf4 edf4;
+       unsigned int reserved[16];
+} __attribute__ ((packed,aligned(8)));
+
+/* ETR interruption parameter */
+struct etr_interruption_parameter {
+       unsigned int _pad0      : 8;
+       unsigned int pc0        : 1;    /* port 0 state change */
+       unsigned int pc1        : 1;    /* port 1 state change */
+       unsigned int _pad1      : 3;
+       unsigned int eai        : 1;    /* ETR alert indication */
+       unsigned int _pad2      : 18;
+} __attribute__ ((packed));
+
+/* Query TOD offset result */
+struct etr_ptff_qto {
+       unsigned long long physical_clock;
+       unsigned long long tod_offset;
+       unsigned long long logical_tod_offset;
+       unsigned long long tod_epoch_difference;
+} __attribute__ ((packed));
+
+/* Inline assembly helper functions */
+static inline int etr_setr(struct etr_eacr *ctrl)
+{
+       int rc = -ENOSYS;
+
+       asm volatile(
+               "       .insn   s,0xb2160000,0(%2)\n"
+               "0:     la      %0,0\n"
+               "1:\n"
+               EX_TABLE(0b,1b)
+               : "+d" (rc) : "m" (*ctrl), "a" (ctrl));
+       return rc;
+}
+
+/* Stores a format 1 aib with 64 bytes */
+static inline int etr_stetr(struct etr_aib *aib)
+{
+       int rc = -ENOSYS;
+
+       asm volatile(
+               "       .insn   s,0xb2170000,0(%2)\n"
+               "0:     la      %0,0\n"
+               "1:\n"
+               EX_TABLE(0b,1b)
+               : "+d" (rc) : "m" (*aib), "a" (aib));
+       return rc;
+}
+
+/* Stores a format 2 aib with 96 bytes for specified port */
+static inline int etr_steai(struct etr_aib *aib, unsigned int func)
+{
+       register unsigned int reg0 asm("0") = func;
+       int rc = -ENOSYS;
+
+       asm volatile(
+               "       .insn   s,0xb2b30000,0(%2)\n"
+               "0:     la      %0,0\n"
+               "1:\n"
+               EX_TABLE(0b,1b)
+               : "+d" (rc) : "m" (*aib), "a" (aib), "d" (reg0));
+       return rc;
+}
+
+/* Function codes for the steai instruction. */
+#define ETR_STEAI_STEPPING_PORT                0x10
+#define ETR_STEAI_ALTERNATE_PORT       0x11
+#define ETR_STEAI_PORT_0               0x12
+#define ETR_STEAI_PORT_1               0x13
+
+static inline int etr_ptff(void *ptff_block, unsigned int func)
+{
+       register unsigned int reg0 asm("0") = func;
+       register unsigned long reg1 asm("1") = (unsigned long) ptff_block;
+       int rc = -ENOSYS;
+
+       asm volatile(
+               "       .word   0x0104\n"
+               "       ipm     %0\n"
+               "       srl     %0,28\n"
+               : "=d" (rc), "=m" (ptff_block)
+               : "d" (reg0), "d" (reg1), "m" (ptff_block) : "cc");
+       return rc;
+}
+
+/* Function codes for the ptff instruction. */
+#define ETR_PTFF_QAF   0x00    /* query available functions */
+#define ETR_PTFF_QTO   0x01    /* query tod offset */
+#define ETR_PTFF_QSI   0x02    /* query steering information */
+#define ETR_PTFF_ATO   0x40    /* adjust tod offset */
+#define ETR_PTFF_STO   0x41    /* set tod offset */
+#define ETR_PTFF_SFS   0x42    /* set fine steering rate */
+#define ETR_PTFF_SGS   0x43    /* set gross steering rate */
+
+/* Functions needed by the machine check handler */
+extern void etr_switch_to_local(void);
+extern void etr_sync_check(void);
+
+#endif /* __S390_ETR_H */
index c2f6a87..31beb18 100644 (file)
@@ -32,6 +32,6 @@ typedef struct {
 
 #define HARDIRQ_BITS   8
 
-extern void account_ticks(void);
+extern void account_ticks(u64 time);
 
 #endif /* __ASM_HARDIRQ_H */
index efb7de9..a4c2d55 100644 (file)
@@ -28,11 +28,7 @@ static inline unsigned long virt_to_phys(volatile void * address)
 {
        unsigned long real_address;
        asm volatile(
-#ifndef __s390x__
                 "      lra     %0,0(%1)\n"
-#else /* __s390x__ */
-                "      lrag    %0,0(%1)\n"
-#endif /* __s390x__ */
                 "      jz      0f\n"
                 "      la      %0,0\n"
                  "0:"
index 40cc680..1b50f89 100644 (file)
@@ -26,7 +26,6 @@ extern int register_page_fault_notifier(struct notifier_block *);
 extern int unregister_page_fault_notifier(struct notifier_block *);
 extern struct atomic_notifier_head s390die_chain;
 
-
 enum die_val {
        DIE_OOPS = 1,
        DIE_BPT,
@@ -56,4 +55,6 @@ static inline int notify_die(enum die_val val, const char *str,
        return atomic_notifier_call_chain(&s390die_chain, val, &args);
 }
 
+extern void die(const char *, struct pt_regs *, long);
+
 #endif
index 74f7389..4a31d0a 100644 (file)
@@ -220,7 +220,8 @@ struct _lowcore
        __u32        kernel_asce;              /* 0xc4c */
        __u32        user_asce;                /* 0xc50 */
        __u32        panic_stack;              /* 0xc54 */
-       __u8         pad10[0xc60-0xc58];       /* 0xc58 */
+       __u32        user_exec_asce;           /* 0xc58 */
+       __u8         pad10[0xc60-0xc5c];       /* 0xc5c */
        /* entry.S sensitive area start */
        struct       cpuinfo_S390 cpu_data;    /* 0xc60 */
        __u32        ipl_device;               /* 0xc7c */
@@ -310,7 +311,8 @@ struct _lowcore
        __u64        kernel_asce;              /* 0xd58 */
        __u64        user_asce;                /* 0xd60 */
        __u64        panic_stack;              /* 0xd68 */
-       __u8         pad10[0xd80-0xd70];       /* 0xd70 */
+       __u64        user_exec_asce;           /* 0xd70 */
+       __u8         pad10[0xd80-0xd78];       /* 0xd78 */
        /* entry.S sensitive area start */
        struct       cpuinfo_S390 cpu_data;    /* 0xd80 */
        __u32        ipl_device;               /* 0xdb8 */
index bcf24a8..1d21da2 100644 (file)
@@ -9,6 +9,7 @@
 #ifndef __S390_MMU_CONTEXT_H
 #define __S390_MMU_CONTEXT_H
 
+#include <asm/pgalloc.h>
 /*
  * get a new mmu context.. S390 don't know about contexts.
  */
 
 #define destroy_context(mm)             do { } while (0)
 
+#ifndef __s390x__
+#define LCTL_OPCODE "lctl"
+#define PGTABLE_BITS (_SEGMENT_TABLE|USER_STD_MASK)
+#else
+#define LCTL_OPCODE "lctlg"
+#define PGTABLE_BITS (_REGION_TABLE|USER_STD_MASK)
+#endif
+
 static inline void enter_lazy_tlb(struct mm_struct *mm,
                                   struct task_struct *tsk)
 {
 }
 
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
-                             struct task_struct *tsk)
+                            struct task_struct *tsk)
 {
-        if (prev != next) {
-#ifndef __s390x__
-               S390_lowcore.user_asce = (__pa(next->pgd)&PAGE_MASK) |
-                      (_SEGMENT_TABLE|USER_STD_MASK);
-                /* Load home space page table origin. */
-                asm volatile("lctl  13,13,%0"
-                            : : "m" (S390_lowcore.user_asce) );
-#else /* __s390x__ */
-                S390_lowcore.user_asce = (__pa(next->pgd) & PAGE_MASK) |
-                       (_REGION_TABLE|USER_STD_MASK);
-               /* Load home space page table origin. */
-               asm volatile("lctlg  13,13,%0"
-                            : : "m" (S390_lowcore.user_asce) );
-#endif /* __s390x__ */
-        }
+       pgd_t *shadow_pgd = get_shadow_pgd(next->pgd);
+
+       if (prev != next) {
+               S390_lowcore.user_asce = (__pa(next->pgd) & PAGE_MASK) |
+                                        PGTABLE_BITS;
+               if (shadow_pgd) {
+                       /* Load primary/secondary space page table origin. */
+                       S390_lowcore.user_exec_asce =
+                               (__pa(shadow_pgd) & PAGE_MASK) | PGTABLE_BITS;
+                       asm volatile(LCTL_OPCODE" 1,1,%0\n"
+                                    LCTL_OPCODE" 7,7,%1"
+                                    : : "m" (S390_lowcore.user_exec_asce),
+                                        "m" (S390_lowcore.user_asce) );
+               } else if (switch_amode) {
+                       /* Load primary space page table origin. */
+                       asm volatile(LCTL_OPCODE" 1,1,%0"
+                                    : : "m" (S390_lowcore.user_asce) );
+               } else
+                       /* Load home space page table origin. */
+                       asm volatile(LCTL_OPCODE" 13,13,%0"
+                                    : : "m" (S390_lowcore.user_asce) );
+       }
        cpu_set(smp_processor_id(), next->cpu_vm_mask);
 }
 
@@ -51,4 +67,4 @@ static inline void activate_mm(struct mm_struct *prev,
        set_fs(current->thread.mm_segment);
 }
 
-#endif
+#endif /* __S390_MMU_CONTEXT_H */
index 0707a7e..56c8a6c 100644 (file)
@@ -47,6 +47,17 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
        if (!pgd)
                return NULL;
+       if (s390_noexec) {
+               pgd_t *shadow_pgd = (pgd_t *)
+                       __get_free_pages(GFP_KERNEL, PGD_ALLOC_ORDER);
+               struct page *page = virt_to_page(pgd);
+
+               if (!shadow_pgd) {
+                       free_pages((unsigned long) pgd, PGD_ALLOC_ORDER);
+                       return NULL;
+               }
+               page->lru.next = (void *) shadow_pgd;
+       }
        for (i = 0; i < PTRS_PER_PGD; i++)
 #ifndef __s390x__
                pmd_clear(pmd_offset(pgd + i, i*PGDIR_SIZE));
@@ -58,6 +69,10 @@ static inline pgd_t *pgd_alloc(struct mm_struct *mm)
 
 static inline void pgd_free(pgd_t *pgd)
 {
+       pgd_t *shadow_pgd = get_shadow_pgd(pgd);
+
+       if (shadow_pgd)
+               free_pages((unsigned long) shadow_pgd, PGD_ALLOC_ORDER);
        free_pages((unsigned long) pgd, PGD_ALLOC_ORDER);
 }
 
@@ -71,6 +86,7 @@ static inline void pgd_free(pgd_t *pgd)
 #define pmd_free(x)                     do { } while (0)
 #define __pmd_free_tlb(tlb,x)          do { } while (0)
 #define pgd_populate(mm, pmd, pte)      BUG()
+#define pgd_populate_kernel(mm, pmd, pte)      BUG()
 #else /* __s390x__ */
 static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 {
@@ -79,6 +95,17 @@ static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 
        if (!pmd)
                return NULL;
+       if (s390_noexec) {
+               pmd_t *shadow_pmd = (pmd_t *)
+                       __get_free_pages(GFP_KERNEL, PMD_ALLOC_ORDER);
+               struct page *page = virt_to_page(pmd);
+
+               if (!shadow_pmd) {
+                       free_pages((unsigned long) pmd, PMD_ALLOC_ORDER);
+                       return NULL;
+               }
+               page->lru.next = (void *) shadow_pmd;
+       }
        for (i=0; i < PTRS_PER_PMD; i++)
                pmd_clear(pmd + i);
        return pmd;
@@ -86,6 +113,10 @@ static inline pmd_t * pmd_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 
 static inline void pmd_free (pmd_t *pmd)
 {
+       pmd_t *shadow_pmd = get_shadow_pmd(pmd);
+
+       if (shadow_pmd)
+               free_pages((unsigned long) shadow_pmd, PMD_ALLOC_ORDER);
        free_pages((unsigned long) pmd, PMD_ALLOC_ORDER);
 }
 
@@ -95,11 +126,22 @@ static inline void pmd_free (pmd_t *pmd)
                pmd_free(pmd);                  \
         } while (0)
 
-static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+static inline void
+pgd_populate_kernel(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
 {
        pgd_val(*pgd) = _PGD_ENTRY | __pa(pmd);
 }
 
+static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pmd_t *pmd)
+{
+       pgd_t *shadow_pgd = get_shadow_pgd(pgd);
+       pmd_t *shadow_pmd = get_shadow_pmd(pmd);
+
+       if (shadow_pgd && shadow_pmd)
+               pgd_populate_kernel(mm, shadow_pgd, shadow_pmd);
+       pgd_populate_kernel(mm, pgd, pmd);
+}
+
 #endif /* __s390x__ */
 
 static inline void 
@@ -119,7 +161,13 @@ pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd, pte_t *pte)
 static inline void
 pmd_populate(struct mm_struct *mm, pmd_t *pmd, struct page *page)
 {
-       pmd_populate_kernel(mm, pmd, (pte_t *)page_to_phys(page));
+       pte_t *pte = (pte_t *)page_to_phys(page);
+       pmd_t *shadow_pmd = get_shadow_pmd(pmd);
+       pte_t *shadow_pte = get_shadow_pte(pte);
+
+       pmd_populate_kernel(mm, pmd, pte);
+       if (shadow_pmd && shadow_pte)
+               pmd_populate_kernel(mm, shadow_pmd, shadow_pte);
 }
 
 /*
@@ -133,6 +181,17 @@ pte_alloc_one_kernel(struct mm_struct *mm, unsigned long vmaddr)
 
        if (!pte)
                return NULL;
+       if (s390_noexec) {
+               pte_t *shadow_pte = (pte_t *)
+                       __get_free_page(GFP_KERNEL|__GFP_REPEAT);
+               struct page *page = virt_to_page(pte);
+
+               if (!shadow_pte) {
+                       free_page((unsigned long) pte);
+                       return NULL;
+               }
+               page->lru.next = (void *) shadow_pte;
+       }
        for (i=0; i < PTRS_PER_PTE; i++) {
                pte_clear(mm, vmaddr, pte + i);
                vmaddr += PAGE_SIZE;
@@ -151,14 +210,30 @@ pte_alloc_one(struct mm_struct *mm, unsigned long vmaddr)
 
 static inline void pte_free_kernel(pte_t *pte)
 {
-        free_page((unsigned long) pte);
+       pte_t *shadow_pte = get_shadow_pte(pte);
+
+       if (shadow_pte)
+               free_page((unsigned long) shadow_pte);
+       free_page((unsigned long) pte);
 }
 
 static inline void pte_free(struct page *pte)
 {
-        __free_page(pte);
+       struct page *shadow_page = get_shadow_page(pte);
+
+       if (shadow_page)
+               __free_page(shadow_page);
+       __free_page(pte);
 }
 
-#define __pte_free_tlb(tlb,pte) tlb_remove_page(tlb,pte)
+#define __pte_free_tlb(tlb, pte)                                       \
+({                                                                     \
+       struct mmu_gather *__tlb = (tlb);                               \
+       struct page *__pte = (pte);                                     \
+       struct page *shadow_page = get_shadow_page(__pte);              \
+       if (shadow_page)                                                \
+               tlb_remove_page(__tlb, shadow_page);                    \
+       tlb_remove_page(__tlb, __pte);                                  \
+})
 
 #endif /* _S390_PGALLOC_H */
index ae61aca..13c1654 100644 (file)
@@ -40,6 +40,7 @@ struct mm_struct;
 
 extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096)));
 extern void paging_init(void);
+extern void vmem_map_init(void);
 
 /*
  * The S390 doesn't have any external MMU info: the kernel page
@@ -223,6 +224,8 @@ extern unsigned long vmalloc_end;
 #define _PAGE_TYPE_FILE                0x601   /* bit 0x002 is used for offset !! */
 #define _PAGE_TYPE_RO          0x200
 #define _PAGE_TYPE_RW          0x000
+#define _PAGE_TYPE_EX_RO       0x202
+#define _PAGE_TYPE_EX_RW       0x002
 
 /*
  * PTE type bits are rather complicated. handle_pte_fault uses pte_present,
@@ -243,11 +246,13 @@ extern unsigned long vmalloc_end;
  * _PAGE_TYPE_FILE     11?1   ->   11?1
  * _PAGE_TYPE_RO       0100   ->   1100
  * _PAGE_TYPE_RW       0000   ->   1000
+ * _PAGE_TYPE_EX_RO    0110   ->   1110
+ * _PAGE_TYPE_EX_RW    0010   ->   1010
  *
- * pte_none is true for bits combinations 1000, 1100
+ * pte_none is true for bits combinations 1000, 1010, 1100, 1110
  * pte_present is true for bits combinations 0000, 0010, 0100, 0110, 1001
  * pte_file is true for bits combinations 1101, 1111
- * swap pte is 1011 and 0001, 0011, 0101, 0111, 1010 and 1110 are invalid.
+ * swap pte is 1011 and 0001, 0011, 0101, 0111 are invalid.
  */
 
 #ifndef __s390x__
@@ -312,33 +317,100 @@ extern unsigned long vmalloc_end;
 #define PAGE_NONE      __pgprot(_PAGE_TYPE_NONE)
 #define PAGE_RO                __pgprot(_PAGE_TYPE_RO)
 #define PAGE_RW                __pgprot(_PAGE_TYPE_RW)
+#define PAGE_EX_RO     __pgprot(_PAGE_TYPE_EX_RO)
+#define PAGE_EX_RW     __pgprot(_PAGE_TYPE_EX_RW)
 
 #define PAGE_KERNEL    PAGE_RW
 #define PAGE_COPY      PAGE_RO
 
 /*
- * The S390 can't do page protection for execute, and considers that the
- * same are read. Also, write permissions imply read permissions. This is
- * the closest we can get..
+ * Dependent on the EXEC_PROTECT option s390 can do execute protection.
+ * Write permission always implies read permission. In theory with a
+ * primary/secondary page table execute only can be implemented but
+ * it would cost an additional bit in the pte to distinguish all the
+ * different pte types. To avoid that execute permission currently
+ * implies read permission as well.
  */
          /*xwr*/
 #define __P000 PAGE_NONE
 #define __P001 PAGE_RO
 #define __P010 PAGE_RO
 #define __P011 PAGE_RO
-#define __P100 PAGE_RO
-#define __P101 PAGE_RO
-#define __P110 PAGE_RO
-#define __P111 PAGE_RO
+#define __P100 PAGE_EX_RO
+#define __P101 PAGE_EX_RO
+#define __P110 PAGE_EX_RO
+#define __P111 PAGE_EX_RO
 
 #define __S000 PAGE_NONE
 #define __S001 PAGE_RO
 #define __S010 PAGE_RW
 #define __S011 PAGE_RW
-#define __S100 PAGE_RO
-#define __S101 PAGE_RO
-#define __S110 PAGE_RW
-#define __S111 PAGE_RW
+#define __S100 PAGE_EX_RO
+#define __S101 PAGE_EX_RO
+#define __S110 PAGE_EX_RW
+#define __S111 PAGE_EX_RW
+
+#ifndef __s390x__
+# define PMD_SHADOW_SHIFT      1
+# define PGD_SHADOW_SHIFT      1
+#else /* __s390x__ */
+# define PMD_SHADOW_SHIFT      2
+# define PGD_SHADOW_SHIFT      2
+#endif /* __s390x__ */
+
+static inline struct page *get_shadow_page(struct page *page)
+{
+       if (s390_noexec && !list_empty(&page->lru))
+               return virt_to_page(page->lru.next);
+       return NULL;
+}
+
+static inline pte_t *get_shadow_pte(pte_t *ptep)
+{
+       unsigned long pteptr = (unsigned long) (ptep);
+
+       if (s390_noexec) {
+               unsigned long offset = pteptr & (PAGE_SIZE - 1);
+               void *addr = (void *) (pteptr ^ offset);
+               struct page *page = virt_to_page(addr);
+               if (!list_empty(&page->lru))
+                       return (pte_t *) ((unsigned long) page->lru.next |
+                                                               offset);
+       }
+       return NULL;
+}
+
+static inline pmd_t *get_shadow_pmd(pmd_t *pmdp)
+{
+       unsigned long pmdptr = (unsigned long) (pmdp);
+
+       if (s390_noexec) {
+               unsigned long offset = pmdptr &
+                               ((PAGE_SIZE << PMD_SHADOW_SHIFT) - 1);
+               void *addr = (void *) (pmdptr ^ offset);
+               struct page *page = virt_to_page(addr);
+               if (!list_empty(&page->lru))
+                       return (pmd_t *) ((unsigned long) page->lru.next |
+                                                               offset);
+       }
+       return NULL;
+}
+
+static inline pgd_t *get_shadow_pgd(pgd_t *pgdp)
+{
+       unsigned long pgdptr = (unsigned long) (pgdp);
+
+       if (s390_noexec) {
+               unsigned long offset = pgdptr &
+                               ((PAGE_SIZE << PGD_SHADOW_SHIFT) - 1);
+               void *addr = (void *) (pgdptr ^ offset);
+               struct page *page = virt_to_page(addr);
+               if (!list_empty(&page->lru))
+                       return (pgd_t *) ((unsigned long) page->lru.next |
+                                                               offset);
+       }
+       return NULL;
+}
 
 /*
  * Certain architectures need to do special things when PTEs
@@ -347,7 +419,16 @@ extern unsigned long vmalloc_end;
  */
 static inline void set_pte(pte_t *pteptr, pte_t pteval)
 {
+       pte_t *shadow_pte = get_shadow_pte(pteptr);
+
        *pteptr = pteval;
+       if (shadow_pte) {
+               if (!(pte_val(pteval) & _PAGE_INVALID) &&
+                   (pte_val(pteval) & _PAGE_SWX))
+                       pte_val(*shadow_pte) = pte_val(pteval) | _PAGE_RO;
+               else
+                       pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY;
+       }
 }
 #define set_pte_at(mm,addr,ptep,pteval) set_pte(ptep,pteval)
 
@@ -465,7 +546,7 @@ static inline int pte_read(pte_t pte)
 
 static inline void pgd_clear(pgd_t * pgdp)      { }
 
-static inline void pmd_clear(pmd_t * pmdp)
+static inline void pmd_clear_kernel(pmd_t * pmdp)
 {
        pmd_val(pmdp[0]) = _PAGE_TABLE_INV;
        pmd_val(pmdp[1]) = _PAGE_TABLE_INV;
@@ -473,24 +554,55 @@ static inline void pmd_clear(pmd_t * pmdp)
        pmd_val(pmdp[3]) = _PAGE_TABLE_INV;
 }
 
+static inline void pmd_clear(pmd_t * pmdp)
+{
+       pmd_t *shadow_pmd = get_shadow_pmd(pmdp);
+
+       pmd_clear_kernel(pmdp);
+       if (shadow_pmd)
+               pmd_clear_kernel(shadow_pmd);
+}
+
 #else /* __s390x__ */
 
-static inline void pgd_clear(pgd_t * pgdp)
+static inline void pgd_clear_kernel(pgd_t * pgdp)
 {
        pgd_val(*pgdp) = _PGD_ENTRY_INV | _PGD_ENTRY;
 }
 
-static inline void pmd_clear(pmd_t * pmdp)
+static inline void pgd_clear(pgd_t * pgdp)
+{
+       pgd_t *shadow_pgd = get_shadow_pgd(pgdp);
+
+       pgd_clear_kernel(pgdp);
+       if (shadow_pgd)
+               pgd_clear_kernel(shadow_pgd);
+}
+
+static inline void pmd_clear_kernel(pmd_t * pmdp)
 {
        pmd_val(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY;
        pmd_val1(*pmdp) = _PMD_ENTRY_INV | _PMD_ENTRY;
 }
 
+static inline void pmd_clear(pmd_t * pmdp)
+{
+       pmd_t *shadow_pmd = get_shadow_pmd(pmdp);
+
+       pmd_clear_kernel(pmdp);
+       if (shadow_pmd)
+               pmd_clear_kernel(shadow_pmd);
+}
+
 #endif /* __s390x__ */
 
 static inline void pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
 {
+       pte_t *shadow_pte = get_shadow_pte(ptep);
+
        pte_val(*ptep) = _PAGE_TYPE_EMPTY;
+       if (shadow_pte)
+               pte_val(*shadow_pte) = _PAGE_TYPE_EMPTY;
 }
 
 /*
@@ -608,8 +720,11 @@ ptep_clear_flush(struct vm_area_struct *vma,
                 unsigned long address, pte_t *ptep)
 {
        pte_t pte = *ptep;
+       pte_t *shadow_pte = get_shadow_pte(ptep);
 
        __ptep_ipte(address, ptep);
+       if (shadow_pte)
+               __ptep_ipte(address, shadow_pte);
        return pte;
 }
 
index cbbedc6..4c1b739 100644 (file)
@@ -50,6 +50,7 @@ struct cpuinfo_S390
         unsigned long pgtable_cache_sz;
 };
 
+extern void s390_adjust_jiffies(void);
 extern void print_cpu_info(struct cpuinfo_S390 *);
 
 /* Lazy FPU handling on uni-processor */
@@ -144,7 +145,8 @@ struct stack_frame {
 #ifndef __s390x__
 
 #define start_thread(regs, new_psw, new_stackp) do {            \
-        regs->psw.mask  = PSW_USER_BITS;                        \
+       set_fs(USER_DS);                                        \
+       regs->psw.mask  = psw_user_bits;                        \
         regs->psw.addr  = new_psw | PSW_ADDR_AMODE;             \
         regs->gprs[15]  = new_stackp ;                          \
 } while (0)
@@ -152,13 +154,15 @@ struct stack_frame {
 #else /* __s390x__ */
 
 #define start_thread(regs, new_psw, new_stackp) do {            \
-        regs->psw.mask  = PSW_USER_BITS;                        \
+       set_fs(USER_DS);                                        \
+       regs->psw.mask  = psw_user_bits;                        \
         regs->psw.addr  = new_psw;                              \
         regs->gprs[15]  = new_stackp;                           \
 } while (0)
 
 #define start_thread31(regs, new_psw, new_stackp) do {          \
-       regs->psw.mask  = PSW_USER32_BITS;                      \
+       set_fs(USER_DS);                                        \
+       regs->psw.mask  = psw_user32_bits;                      \
         regs->psw.addr  = new_psw;                              \
         regs->gprs[15]  = new_stackp;                           \
 } while (0)
@@ -201,9 +205,8 @@ unsigned long get_wchan(struct task_struct *p);
 static inline void cpu_relax(void)
 {
        if (MACHINE_HAS_DIAG44)
-               asm volatile("diag 0,0,68" : : : "memory");
-       else
-               barrier();
+               asm volatile("diag 0,0,68");
+       barrier();
 }
 
 /*
@@ -327,6 +330,18 @@ static inline void disabled_wait(unsigned long code)
 #endif /* __s390x__ */
 }
 
+/*
+ * Basic Machine Check/Program Check Handler.
+ */
+
+extern void s390_base_mcck_handler(void);
+extern void s390_base_pgm_handler(void);
+extern void s390_base_ext_handler(void);
+
+extern void (*s390_base_mcck_handler_fn)(void);
+extern void (*s390_base_pgm_handler_fn)(void);
+extern void (*s390_base_ext_handler_fn)(void);
+
 /*
  * CPU idle notifier chain.
  */
index 7b768c5..fa6ca87 100644 (file)
@@ -266,17 +266,12 @@ typedef struct
 #define PSW_ASC_SECONDARY      0x0000800000000000UL
 #define PSW_ASC_HOME           0x0000C00000000000UL
 
-#define PSW_USER32_BITS (PSW_BASE32_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
-                        PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
-                        PSW_MASK_PSTATE | PSW_DEFAULT_KEY)
+extern long psw_user32_bits;
 
 #endif /* __s390x__ */
 
-#define PSW_KERNEL_BITS        (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | \
-                        PSW_MASK_MCHECK | PSW_DEFAULT_KEY)
-#define PSW_USER_BITS  (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
-                        PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
-                        PSW_MASK_PSTATE | PSW_DEFAULT_KEY)
+extern long psw_kernel_bits;
+extern long psw_user_bits;
 
 /* This macro merges a NEW PSW mask specified by the user into
    the currently active PSW mask CURRENT, modifying only those
index 532e65a..f584f4a 100644 (file)
@@ -18,7 +18,4 @@ struct reset_call {
 extern void register_reset_call(struct reset_call *reset);
 extern void unregister_reset_call(struct reset_call *reset);
 extern void s390_reset_system(void);
-extern void (*s390_reset_mcck_handler)(void);
-extern void (*s390_reset_pgm_handler)(void);
-
 #endif /* _ASM_S390_RESET_H */
diff --git a/include/asm-s390/sclp.h b/include/asm-s390/sclp.h
new file mode 100644 (file)
index 0000000..468b970
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ *  include/asm-s390/sclp.h
+ *
+ *    Copyright IBM Corp. 2007
+ *    Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ */
+
+#ifndef _ASM_S390_SCLP_H
+#define _ASM_S390_SCLP_H
+
+#include <linux/types.h>
+
+struct sccb_header {
+       u16     length;
+       u8      function_code;
+       u8      control_mask[3];
+       u16     response_code;
+} __attribute__((packed));
+
+#define LOADPARM_LEN 8
+
+struct sclp_readinfo_sccb {
+       struct  sccb_header header;     /* 0-7 */
+       u16     rnmax;                  /* 8-9 */
+       u8      rnsize;                 /* 10 */
+       u8      _reserved0[24 - 11];    /* 11-23 */
+       u8      loadparm[LOADPARM_LEN]; /* 24-31 */
+       u8      _reserved1[91 - 32];    /* 32-90 */
+       u8      flags;                  /* 91 */
+       u8      _reserved2[100 - 92];   /* 92-99 */
+       u32     rnsize2;                /* 100-103 */
+       u64     rnmax2;                 /* 104-111 */
+       u8      _reserved3[4096 - 112]; /* 112-4095 */
+} __attribute__((packed, aligned(4096)));
+
+extern struct sclp_readinfo_sccb s390_readinfo_sccb;
+extern void sclp_readinfo_early(void);
+
+#endif /* _ASM_S390_SCLP_H */
index 3a0b8ff..1c5a2c4 100644 (file)
@@ -3,4 +3,6 @@
 
 #include <asm-generic/sections.h>
 
+extern char _eshared[];
+
 #endif
index 9574fe8..3388bb5 100644 (file)
@@ -42,6 +42,18 @@ struct mem_chunk {
 
 extern struct mem_chunk memory_chunk[];
 
+#ifdef CONFIG_S390_SWITCH_AMODE
+extern unsigned int switch_amode;
+#else
+#define switch_amode   (0)
+#endif
+
+#ifdef CONFIG_S390_EXEC_PROTECT
+extern unsigned int s390_noexec;
+#else
+#define s390_noexec    (0)
+#endif
+
 /*
  * Machine features detected in head.S
  */
@@ -74,6 +86,9 @@ extern unsigned int console_mode;
 extern unsigned int console_devno;
 extern unsigned int console_irq;
 
+extern char vmhalt_cmd[];
+extern char vmpoff_cmd[];
+
 #define CONSOLE_IS_UNDEFINED   (console_mode == 0)
 #define CONSOLE_IS_SCLP                (console_mode == 1)
 #define CONSOLE_IS_3215                (console_mode == 2)
@@ -141,13 +156,19 @@ struct ipl_parameter_block {
 extern u32 ipl_flags;
 extern u16 ipl_devno;
 
-void do_reipl(void);
+extern void do_reipl(void);
+extern void ipl_save_parameters(void);
 
 enum {
        IPL_DEVNO_VALID = 1,
        IPL_PARMBLOCK_VALID = 2,
+       IPL_NSS_VALID = 4,
 };
 
+#define NSS_NAME_SIZE  8
+
+extern char kernel_nss_name[];
+
 #define IPL_PARMBLOCK_START    ((struct ipl_parameter_block *) \
                                 IPL_PARMBLOCK_ORIGIN)
 #define IPL_PARMBLOCK_SIZE     (IPL_PARMBLOCK_START->hdr.len)
diff --git a/include/asm-s390/sfp-util.h b/include/asm-s390/sfp-util.h
new file mode 100644 (file)
index 0000000..8cabcd2
--- /dev/null
@@ -0,0 +1,66 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define add_ssaaaa(sh, sl, ah, al, bh, bl) ({          \
+       unsigned int __sh = (ah);                       \
+       unsigned int __sl = (al);                       \
+       asm volatile(                                   \
+               "       alr     %1,%3\n"                \
+               "       brc     12,0f\n"                \
+               "       ahi     %0,1\n"                 \
+               "0:     alr  %0,%2"                     \
+               : "+&d" (__sh), "+d" (__sl)             \
+               : "d" (bh), "d" (bl) : "cc");           \
+       (sh) = __sh;                                    \
+       (sl) = __sl;                                    \
+})
+
+#define sub_ddmmss(sh, sl, ah, al, bh, bl) ({          \
+       unsigned int __sh = (ah);                       \
+       unsigned int __sl = (al);                       \
+       asm volatile(                                   \
+               "       slr     %1,%3\n"                \
+               "       brc     3,0f\n"                 \
+               "       ahi     %0,-1\n"                \
+               "0:     slr     %0,%2"                  \
+               : "+&d" (__sh), "+d" (__sl)             \
+               : "d" (bh), "d" (bl) : "cc");           \
+       (sh) = __sh;                                    \
+       (sl) = __sl;                                    \
+})
+
+/* a umul b = a mul b + (a>=2<<31) ? b<<32:0 + (b>=2<<31) ? a<<32:0 */
+#define umul_ppmm(wh, wl, u, v) ({                     \
+       unsigned int __wh = u;                          \
+       unsigned int __wl = v;                          \
+       asm volatile(                                   \
+               "       ltr     1,%0\n"                 \
+               "       mr      0,%1\n"                 \
+               "       jnm     0f\n"                           \
+               "       alr     0,%1\n"                 \
+               "0:     ltr     %1,%1\n"                        \
+               "       jnm     1f\n"                           \
+               "       alr     0,%0\n"                 \
+               "1:     lr      %0,0\n"                 \
+               "       lr      %1,1\n"                 \
+               : "+d" (__wh), "+d" (__wl)              \
+               : : "0", "1", "cc");                    \
+       wh = __wh;                                      \
+       wl = __wl;                                      \
+})
+
+#define udiv_qrnnd(q, r, n1, n0, d)                    \
+  do { unsigned int __r;                               \
+    (q) = __udiv_qrnnd (&__r, (n1), (n0), (d));                \
+    (r) = __r;                                         \
+  } while (0)
+extern unsigned long __udiv_qrnnd (unsigned int *, unsigned int,
+                                  unsigned int , unsigned int);
+
+#define UDIV_NEEDS_NORMALIZATION 0
+
+#define abort() return 0
+
+#define __BYTE_ORDER __BIG_ENDIAN
index 7097c96..b957e4c 100644 (file)
@@ -31,6 +31,10 @@ typedef struct
        __u16      cpu;
 } sigp_info;
 
+extern void machine_restart_smp(char *);
+extern void machine_halt_smp(void);
+extern void machine_power_off_smp(void);
+
 extern void smp_setup_cpu_possible_map(void);
 extern int smp_call_function_on(void (*func) (void *info), void *info,
                                int nonatomic, int wait, int cpu);
@@ -106,7 +110,7 @@ smp_call_function_on(void (*func) (void *info), void *info,
 static inline void smp_send_stop(void)
 {
        /* Disable all interrupts/machine checks */
-       __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK);
+       __load_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK);
 }
 
 #define smp_cpu_not_running(cpu)       1
index bd0b05a..bbe137c 100644 (file)
@@ -373,8 +373,8 @@ __set_psw_mask(unsigned long mask)
        __load_psw_mask(mask | (__raw_local_irq_stosm(0x00) & ~(-1UL >> 8)));
 }
 
-#define local_mcck_enable()  __set_psw_mask(PSW_KERNEL_BITS)
-#define local_mcck_disable() __set_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK)
+#define local_mcck_enable()  __set_psw_mask(psw_kernel_bits)
+#define local_mcck_disable() __set_psw_mask(psw_kernel_bits & ~PSW_MASK_MCHECK)
 
 #ifdef CONFIG_SMP
 
index f1d66ba..884fba4 100644 (file)
@@ -1,11 +1,11 @@
 /*************************************************************************
  *
  * tape390.h
- *         enables user programs to display messages on the tape device
+ *        enables user programs to display messages and control encryption
+ *        on s390 tape devices
  *
- *  S390 and zSeries version
- *         Copyright (C) 2001 IBM Corporation
- *         Author(s): Despina Papadopoulou <despina_p@de.ibm.com>
+ *        Copyright IBM Corp. 2001,2006
+ *        Author(s): Michael Holzheu <holzheu@de.ibm.com>
  *
  *************************************************************************/
 
@@ -36,4 +36,68 @@ typedef struct display_struct {
         char message2[8];
 } display_struct;
 
+/*
+ * Tape encryption support
+ */
+
+struct tape390_crypt_info {
+       char capability;
+       char status;
+       char medium_status;
+} __attribute__ ((packed));
+
+
+/* Macros for "capable" field */
+#define TAPE390_CRYPT_SUPPORTED_MASK 0x01
+#define TAPE390_CRYPT_SUPPORTED(x) \
+       ((x.capability & TAPE390_CRYPT_SUPPORTED_MASK))
+
+/* Macros for "status" field */
+#define TAPE390_CRYPT_ON_MASK 0x01
+#define TAPE390_CRYPT_ON(x) (((x.status) & TAPE390_CRYPT_ON_MASK))
+
+/* Macros for "medium status" field */
+#define TAPE390_MEDIUM_LOADED_MASK 0x01
+#define TAPE390_MEDIUM_ENCRYPTED_MASK 0x02
+#define TAPE390_MEDIUM_ENCRYPTED(x) \
+       (((x.medium_status) & TAPE390_MEDIUM_ENCRYPTED_MASK))
+#define TAPE390_MEDIUM_LOADED(x) \
+       (((x.medium_status) & TAPE390_MEDIUM_LOADED_MASK))
+
+/*
+ * The TAPE390_CRYPT_SET ioctl is used to switch on/off encryption.
+ * The "encryption_capable" and "tape_status" fields are ignored for this ioctl!
+ */
+#define TAPE390_CRYPT_SET _IOW('d', 2, struct tape390_crypt_info)
+
+/*
+ * The TAPE390_CRYPT_QUERY ioctl is used to query the encryption state.
+ */
+#define TAPE390_CRYPT_QUERY _IOR('d', 3, struct tape390_crypt_info)
+
+/* Values for "kekl1/2_type" and "kekl1/2_type_on_tape" fields */
+#define TAPE390_KEKL_TYPE_NONE 0
+#define TAPE390_KEKL_TYPE_LABEL 1
+#define TAPE390_KEKL_TYPE_HASH 2
+
+struct tape390_kekl {
+       unsigned char type;
+       unsigned char type_on_tape;
+       char label[65];
+} __attribute__ ((packed));
+
+struct tape390_kekl_pair {
+       struct tape390_kekl kekl[2];
+} __attribute__ ((packed));
+
+/*
+ * The TAPE390_KEKL_SET ioctl is used to set Key Encrypting Key labels.
+ */
+#define TAPE390_KEKL_SET _IOW('d', 4, struct tape390_kekl_pair)
+
+/*
+ * The TAPE390_KEKL_QUERY ioctl is used to query Key Encrypting Key labels.
+ */
+#define TAPE390_KEKL_QUERY _IOR('d', 5, struct tape390_kekl_pair)
+
 #endif 
index 30e5cbe..adb3486 100644 (file)
@@ -45,6 +45,9 @@ extern void add_virt_timer_periodic(void *new);
 extern int mod_virt_timer(struct vtimer_list *timer, __u64 expires);
 extern int del_virt_timer(struct vtimer_list *timer);
 
+extern void init_cpu_vtimer(void);
+extern void vtime_init(void);
+
 #endif /* __KERNEL__ */
 
 #endif /* _ASM_S390_TIMER_H */
index 4df4a41..98229db 100644 (file)
 #ifndef _ASM_S390_TIMEX_H
 #define _ASM_S390_TIMEX_H
 
+/* Inline functions for clock register access. */
+static inline int set_clock(__u64 time)
+{
+       int cc;
+
+       asm volatile(
+               "   sck   0(%2)\n"
+               "   ipm   %0\n"
+               "   srl   %0,28\n"
+               : "=d" (cc) : "m" (time), "a" (&time) : "cc");
+       return cc;
+}
+
+static inline int store_clock(__u64 *time)
+{
+       int cc;
+
+       asm volatile(
+               "   stck  0(%2)\n"
+               "   ipm   %0\n"
+               "   srl   %0,28\n"
+               : "=d" (cc), "=m" (*time) : "a" (time) : "cc");
+       return cc;
+}
+
+static inline void set_clock_comparator(__u64 time)
+{
+       asm volatile("sckc 0(%1)" : : "m" (time), "a" (&time));
+}
+
+static inline void store_clock_comparator(__u64 *time)
+{
+       asm volatile("stckc 0(%1)" : "=m" (*time) : "a" (time));
+}
+
 #define CLOCK_TICK_RATE        1193180 /* Underlying HZ */
 
 typedef unsigned long long cycles_t;
@@ -27,9 +62,24 @@ static inline unsigned long long get_clock (void)
        return clk;
 }
 
+static inline void get_clock_extended(void *dest)
+{
+       typedef struct { unsigned long long clk[2]; } __clock_t;
+
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
+       asm volatile("stcke %0" : "=Q" (*((__clock_t *)dest)) : : "cc");
+#else /* __GNUC__ */
+       asm volatile("stcke 0(%1)" : "=m" (*((__clock_t *)dest))
+                                  : "a" ((__clock_t *)dest) : "cc");
+#endif /* __GNUC__ */
+}
+
 static inline cycles_t get_cycles(void)
 {
        return (cycles_t) get_clock() >> 2;
 }
 
+int get_sync_clock(unsigned long long *clock);
+void init_cpu_timer(void);
+
 #endif
index fa4dc91..66793f5 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <linux/mm.h>
 #include <asm/processor.h>
+#include <asm/pgalloc.h>
 
 /*
  * TLB flushing:
@@ -102,6 +103,14 @@ static inline void __flush_tlb_mm(struct mm_struct * mm)
        if (unlikely(cpus_empty(mm->cpu_vm_mask)))
                return;
        if (MACHINE_HAS_IDTE) {
+               pgd_t *shadow_pgd = get_shadow_pgd(mm->pgd);
+
+               if (shadow_pgd) {
+                       asm volatile(
+                               "       .insn   rrf,0xb98e0000,0,%0,%1,0"
+                               : : "a" (2048),
+                               "a" (__pa(shadow_pgd) & PAGE_MASK) : "cc" );
+               }
                asm volatile(
                        "       .insn   rrf,0xb98e0000,0,%0,%1,0"
                        : : "a" (2048), "a" (__pa(mm->pgd)&PAGE_MASK) : "cc");
index 73ac4e8..0235970 100644 (file)
@@ -90,6 +90,8 @@ struct uaccess_ops {
 extern struct uaccess_ops uaccess;
 extern struct uaccess_ops uaccess_std;
 extern struct uaccess_ops uaccess_mvcos;
+extern struct uaccess_ops uaccess_mvcos_switch;
+extern struct uaccess_ops uaccess_pt;
 
 static inline int __put_user_fn(size_t size, void __user *ptr, void *x)
 {
index 6b6fc6f..a29f050 100644 (file)
@@ -37,7 +37,7 @@
  * Calling conventions:
  *
  * ACPI_SYSTEM_XFACE        - Interfaces to host OS (handlers, threads)
- * ACPI_EXTERNAL_XFACE      - External ACPI interfaces 
+ * ACPI_EXTERNAL_XFACE      - External ACPI interfaces
  * ACPI_INTERNAL_XFACE      - Internal ACPI interfaces
  * ACPI_INTERNAL_VAR_XFACE  - Internal variable-parameter list interfaces
  */
 int __acpi_acquire_global_lock(unsigned int *lock);
 int __acpi_release_global_lock(unsigned int *lock);
 
-#define ACPI_ACQUIRE_GLOBAL_LOCK(GLptr, Acq) \
-       ((Acq) = __acpi_acquire_global_lock((unsigned int *) GLptr))
+#define ACPI_ACQUIRE_GLOBAL_LOCK(facs, Acq) \
+       ((Acq) = __acpi_acquire_global_lock(&facs->global_lock))
 
-#define ACPI_RELEASE_GLOBAL_LOCK(GLptr, Acq) \
-       ((Acq) = __acpi_release_global_lock((unsigned int *) GLptr))
+#define ACPI_RELEASE_GLOBAL_LOCK(facs, Acq) \
+       ((Acq) = __acpi_release_global_lock(&facs->global_lock))
 
 /*
  * Math helper asm macros
@@ -87,10 +87,10 @@ extern int acpi_strict;
 extern int acpi_disabled;
 extern int acpi_pci_disabled;
 extern int acpi_ht;
-static inline void disable_acpi(void) 
-{ 
-       acpi_disabled = 1; 
-       acpi_ht = 0; 
+static inline void disable_acpi(void)
+{
+       acpi_disabled = 1;
+       acpi_ht = 0;
        acpi_pci_disabled = 1;
        acpi_noirq = 1;
 }
@@ -100,9 +100,9 @@ static inline void disable_acpi(void)
 
 extern int acpi_gsi_to_irq(u32 gsi, unsigned int *irq);
 static inline void acpi_noirq_set(void) { acpi_noirq = 1; }
-static inline void acpi_disable_pci(void) 
+static inline void acpi_disable_pci(void)
 {
-       acpi_pci_disabled = 1; 
+       acpi_pci_disabled = 1;
        acpi_noirq_set();
 }
 extern int acpi_irq_balance_set(char *str);
@@ -136,8 +136,6 @@ extern void acpi_reserve_bootmem(void);
 extern int acpi_disabled;
 extern int acpi_pci_disabled;
 
-extern u8 x86_acpiid_to_apicid[];
-
 #define ARCH_HAS_POWER_INIT 1
 
 extern int acpi_skip_timer_override;
index ba94ab3..ab913ff 100644 (file)
@@ -1,6 +1,5 @@
 #ifndef _ASM_SWIOTLB_H
-#define _ASM_SWTIOLB_H 1
-
+#define _ASM_SWIOTLB_H 1
 
 #include <asm/dma-mapping.h>
 
@@ -45,6 +44,7 @@ extern void swiotlb_init(void);
 extern int swiotlb_force;
 
 #ifdef CONFIG_SWIOTLB
+#define SWIOTLB_ARCH_NEED_ALLOC
 extern int swiotlb;
 #else
 #define swiotlb 0
@@ -52,4 +52,6 @@ extern int swiotlb;
 
 extern void pci_swiotlb_init(void);
 
-#endif /* _ASM_SWTIOLB_H */
+static inline void dma_mark_clean(void *addr, size_t size) {}
+
+#endif /* _ASM_SWIOTLB_H */
index 157db77..683513e 100644 (file)
@@ -11,6 +11,7 @@ header-y += netfilter_arp/
 header-y += netfilter_bridge/
 header-y += netfilter_ipv4/
 header-y += netfilter_ipv6/
+header-y += usb/
 
 header-y += affs_hardblocks.h
 header-y += aio_abi.h
@@ -326,7 +327,6 @@ unifdef-y += udp.h
 unifdef-y += uinput.h
 unifdef-y += uio.h
 unifdef-y += unistd.h
-unifdef-y += usb_ch9.h
 unifdef-y += usbdevice_fs.h
 unifdef-y += user.h
 unifdef-y += utsname.h
index 91f1f23..815f1fb 100644 (file)
@@ -53,166 +53,6 @@ enum acpi_irq_model_id {
 
 extern enum acpi_irq_model_id  acpi_irq_model;
 
-
-/* Root System Description Pointer (RSDP) */
-
-struct acpi_table_rsdp {
-       char                    signature[8];
-       u8                      checksum;
-       char                    oem_id[6];
-       u8                      revision;
-       u32                     rsdt_address;
-} __attribute__ ((packed));
-
-struct acpi20_table_rsdp {
-       char                    signature[8];
-       u8                      checksum;
-       char                    oem_id[6];
-       u8                      revision;
-       u32                     rsdt_address;
-       u32                     length;
-       u64                     xsdt_address;
-       u8                      ext_checksum;
-       u8                      reserved[3];
-} __attribute__ ((packed));
-
-typedef struct {
-       u8                      type;
-       u8                      length;
-} __attribute__ ((packed)) acpi_table_entry_header;
-
-/* Root System Description Table (RSDT) */
-
-struct acpi_table_rsdt {
-       struct acpi_table_header header;
-       u32                     entry[8];
-} __attribute__ ((packed));
-
-/* Extended System Description Table (XSDT) */
-
-struct acpi_table_xsdt {
-       struct acpi_table_header header;
-       u64                     entry[1];
-} __attribute__ ((packed));
-
-/* Fixed ACPI Description Table (FADT) */
-
-struct acpi_table_fadt {
-       struct acpi_table_header header;
-       u32 facs_addr;
-       u32 dsdt_addr;
-       /* ... */
-} __attribute__ ((packed));
-
-/* Multiple APIC Description Table (MADT) */
-
-struct acpi_table_madt {
-       struct acpi_table_header header;
-       u32                     lapic_address;
-       struct {
-               u32                     pcat_compat:1;
-               u32                     reserved:31;
-       }                       flags;
-} __attribute__ ((packed));
-
-enum acpi_madt_entry_id {
-       ACPI_MADT_LAPIC = 0,
-       ACPI_MADT_IOAPIC,
-       ACPI_MADT_INT_SRC_OVR,
-       ACPI_MADT_NMI_SRC,
-       ACPI_MADT_LAPIC_NMI,
-       ACPI_MADT_LAPIC_ADDR_OVR,
-       ACPI_MADT_IOSAPIC,
-       ACPI_MADT_LSAPIC,
-       ACPI_MADT_PLAT_INT_SRC,
-       ACPI_MADT_ENTRY_COUNT
-};
-
-typedef struct {
-       u16                     polarity:2;
-       u16                     trigger:2;
-       u16                     reserved:12;
-} __attribute__ ((packed)) acpi_interrupt_flags;
-
-struct acpi_table_lapic {
-       acpi_table_entry_header header;
-       u8                      acpi_id;
-       u8                      id;
-       struct {
-               u32                     enabled:1;
-               u32                     reserved:31;
-       }                       flags;
-} __attribute__ ((packed));
-
-struct acpi_table_ioapic {
-       acpi_table_entry_header header;
-       u8                      id;
-       u8                      reserved;
-       u32                     address;
-       u32                     global_irq_base;
-} __attribute__ ((packed));
-
-struct acpi_table_int_src_ovr {
-       acpi_table_entry_header header;
-       u8                      bus;
-       u8                      bus_irq;
-       u32                     global_irq;
-       acpi_interrupt_flags    flags;
-} __attribute__ ((packed));
-
-struct acpi_table_nmi_src {
-       acpi_table_entry_header header;
-       acpi_interrupt_flags    flags;
-       u32                     global_irq;
-} __attribute__ ((packed));
-
-struct acpi_table_lapic_nmi {
-       acpi_table_entry_header header;
-       u8                      acpi_id;
-       acpi_interrupt_flags    flags;
-       u8                      lint;
-} __attribute__ ((packed));
-
-struct acpi_table_lapic_addr_ovr {
-       acpi_table_entry_header header;
-       u8                      reserved[2];
-       u64                     address;
-} __attribute__ ((packed));
-
-struct acpi_table_iosapic {
-       acpi_table_entry_header header;
-       u8                      id;
-       u8                      reserved;
-       u32                     global_irq_base;
-       u64                     address;
-} __attribute__ ((packed));
-
-struct acpi_table_lsapic {
-       acpi_table_entry_header header;
-       u8                      acpi_id;
-       u8                      id;
-       u8                      eid;
-       u8                      reserved[3];
-       struct {
-               u32                     enabled:1;
-               u32                     reserved:31;
-       }                       flags;
-} __attribute__ ((packed));
-
-struct acpi_table_plat_int_src {
-       acpi_table_entry_header header;
-       acpi_interrupt_flags    flags;
-       u8                      type;   /* See acpi_interrupt_type */
-       u8                      id;
-       u8                      eid;
-       u8                      iosapic_vector;
-       u32                     global_irq;
-       struct {
-               u32                     cpei_override_flag:1;
-               u32                     reserved:31;
-       }                       plint_flags;
-} __attribute__ ((packed));
-
 enum acpi_interrupt_id {
        ACPI_INTERRUPT_PMI      = 1,
        ACPI_INTERRUPT_INIT,
@@ -222,89 +62,6 @@ enum acpi_interrupt_id {
 
 #define        ACPI_SPACE_MEM          0
 
-struct acpi_gen_regaddr {
-       u8  space_id;
-       u8  bit_width;
-       u8  bit_offset;
-       u8  resv;
-       u32 addrl;
-       u32 addrh;
-} __attribute__ ((packed));
-
-struct acpi_table_hpet {
-       struct acpi_table_header header;
-       u32 id;
-       struct acpi_gen_regaddr addr;
-       u8 number;
-       u16 min_tick;
-       u8 page_protect;
-} __attribute__ ((packed));
-
-/*
- * Simple Boot Flags
- * http://www.microsoft.com/whdc/hwdev/resources/specs/simp_bios.mspx
- */
-struct acpi_table_sbf
-{
-       u8 sbf_signature[4];
-       u32 sbf_len;
-       u8 sbf_revision;
-       u8 sbf_csum;
-       u8 sbf_oemid[6];
-       u8 sbf_oemtable[8];
-       u8 sbf_revdata[4];
-       u8 sbf_creator[4];
-       u8 sbf_crearev[4];
-       u8 sbf_cmos;
-       u8 sbf_spare[3];
-} __attribute__ ((packed));
-
-/*
- * System Resource Affinity Table (SRAT)
- * http://www.microsoft.com/whdc/hwdev/platform/proc/SRAT.mspx
- */
-
-struct acpi_table_srat {
-       struct acpi_table_header header;
-       u32                     table_revision;
-       u64                     reserved;
-} __attribute__ ((packed));
-
-enum acpi_srat_entry_id {
-       ACPI_SRAT_PROCESSOR_AFFINITY = 0,
-       ACPI_SRAT_MEMORY_AFFINITY,
-       ACPI_SRAT_ENTRY_COUNT
-};
-
-struct acpi_table_processor_affinity {
-       acpi_table_entry_header header;
-       u8                      proximity_domain;
-       u8                      apic_id;
-       struct {
-               u32                     enabled:1;
-               u32                     reserved:31;
-       }                       flags;
-       u8                      lsapic_eid;
-       u8                      reserved[7];
-} __attribute__ ((packed));
-
-struct acpi_table_memory_affinity {
-       acpi_table_entry_header header;
-       u8                      proximity_domain;
-       u8                      reserved1[5];
-       u32                     base_addr_lo;
-       u32                     base_addr_hi;
-       u32                     length_lo;
-       u32                     length_hi;
-       u32                     memory_type;    /* See acpi_address_range_id */
-       struct {
-               u32                     enabled:1;
-               u32                     hot_pluggable:1;
-               u32                     reserved:30;
-       }                       flags;
-       u64                     reserved2;
-} __attribute__ ((packed));
-
 enum acpi_address_range_id {
        ACPI_ADDRESS_RANGE_MEMORY = 1,
        ACPI_ADDRESS_RANGE_RESERVED = 2,
@@ -313,84 +70,12 @@ enum acpi_address_range_id {
        ACPI_ADDRESS_RANGE_COUNT
 };
 
-/*
- * System Locality Information Table (SLIT)
- *   see http://devresource.hp.com/devresource/docs/techpapers/ia64/slit.pdf
- */
-
-struct acpi_table_slit {
-       struct acpi_table_header header;
-       u64                     localities;
-       u8                      entry[1];       /* real size = localities^2 */
-} __attribute__ ((packed));
-
-/* Smart Battery Description Table (SBST) */
-
-struct acpi_table_sbst {
-       struct acpi_table_header header;
-       u32                     warning;        /* Warn user */
-       u32                     low;            /* Critical sleep */
-       u32                     critical;       /* Critical shutdown */
-} __attribute__ ((packed));
-
-/* Embedded Controller Boot Resources Table (ECDT) */
-
-struct acpi_table_ecdt {
-       struct acpi_table_header        header;
-       struct acpi_generic_address     ec_control;
-       struct acpi_generic_address     ec_data;
-       u32                             uid;
-       u8                              gpe_bit;
-       char                            ec_id[0];
-} __attribute__ ((packed));
-
-/* PCI MMCONFIG */
-
-/* Defined in PCI Firmware Specification 3.0 */
-struct acpi_table_mcfg_config {
-       u32                             base_address;
-       u32                             base_reserved;
-       u16                             pci_segment_group_number;
-       u8                              start_bus_number;
-       u8                              end_bus_number;
-       u8                              reserved[4];
-} __attribute__ ((packed));
-struct acpi_table_mcfg {
-       struct acpi_table_header        header;
-       u8                              reserved[8];
-       struct acpi_table_mcfg_config   config[0];
-} __attribute__ ((packed));
 
 /* Table Handlers */
 
-enum acpi_table_id {
-       ACPI_TABLE_UNKNOWN = 0,
-       ACPI_APIC,
-       ACPI_BOOT,
-       ACPI_DBGP,
-       ACPI_DSDT,
-       ACPI_ECDT,
-       ACPI_ETDT,
-       ACPI_FADT,
-       ACPI_FACS,
-       ACPI_OEMX,
-       ACPI_PSDT,
-       ACPI_SBST,
-       ACPI_SLIT,
-       ACPI_SPCR,
-       ACPI_SRAT,
-       ACPI_SSDT,
-       ACPI_SPMI,
-       ACPI_HPET,
-       ACPI_MCFG,
-       ACPI_TABLE_COUNT
-};
-
-typedef int (*acpi_table_handler) (unsigned long phys_addr, unsigned long size);
-
-extern acpi_table_handler acpi_table_ops[ACPI_TABLE_COUNT];
+typedef int (*acpi_table_handler) (struct acpi_table_header *table);
 
-typedef int (*acpi_madt_entry_handler) (acpi_table_entry_header *header, const unsigned long end);
+typedef int (*acpi_madt_entry_handler) (struct acpi_subtable_header *header, const unsigned long end);
 
 char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
 unsigned long acpi_find_rsdp (void);
@@ -399,14 +84,12 @@ int acpi_boot_table_init (void);
 int acpi_numa_init (void);
 
 int acpi_table_init (void);
-int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler);
-int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header);
-int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries);
-int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries);
-int acpi_parse_mcfg (unsigned long phys_addr, unsigned long size);
-void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr);
-void acpi_table_print_madt_entry (acpi_table_entry_header *madt);
-void acpi_table_print_srat_entry (acpi_table_entry_header *srat);
+int acpi_table_parse (char *id, acpi_table_handler handler);
+int acpi_table_parse_madt (enum acpi_madt_type id, acpi_madt_entry_handler handler, unsigned int max_entries);
+int acpi_table_parse_srat (enum acpi_srat_type id, acpi_madt_entry_handler handler, unsigned int max_entries);
+int acpi_parse_mcfg (struct acpi_table_header *header);
+void acpi_table_print_madt_entry (struct acpi_subtable_header *madt);
+void acpi_table_print_srat_entry (struct acpi_subtable_header *srat);
 
 /* the following four functions are architecture-dependent */
 #ifdef CONFIG_HAVE_ARCH_PARSE_SRAT
@@ -417,8 +100,8 @@ void acpi_table_print_srat_entry (acpi_table_entry_header *srat);
 #define acpi_numa_arch_fixup() do {} while (0)
 #else
 void acpi_numa_slit_init (struct acpi_table_slit *slit);
-void acpi_numa_processor_affinity_init (struct acpi_table_processor_affinity *pa);
-void acpi_numa_memory_affinity_init (struct acpi_table_memory_affinity *ma);
+void acpi_numa_processor_affinity_init (struct acpi_srat_cpu_affinity *pa);
+void acpi_numa_memory_affinity_init (struct acpi_srat_mem_affinity *ma);
 void acpi_numa_arch_fixup(void);
 #endif
 
@@ -433,7 +116,7 @@ int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base);
 
 extern int acpi_mp_config;
 
-extern struct acpi_table_mcfg_config *pci_mmcfg_config;
+extern struct acpi_mcfg_allocation *pci_mmcfg_config;
 extern int pci_mmcfg_config_num;
 
 extern int sbf_port;
index f44247f..5ca1cdb 100644 (file)
@@ -126,6 +126,7 @@ struct device_driver {
        struct klist_node       knode_bus;
 
        struct module           * owner;
+       const char              * mod_name;     /* used for built-in modules */
 
        int     (*probe)        (struct device * dev);
        int     (*remove)       (struct device * dev);
@@ -327,6 +328,13 @@ extern struct class_device *class_device_create(struct class *cls,
                                        __attribute__((format(printf,5,6)));
 extern void class_device_destroy(struct class *cls, dev_t devt);
 
+struct device_type {
+       struct device_attribute *attrs;
+       int (*uevent)(struct device *dev, char **envp, int num_envp,
+                     char *buffer, int buffer_size);
+       void (*release)(struct device *dev);
+};
+
 /* interface for exporting device attributes */
 struct device_attribute {
        struct attribute        attr;
@@ -355,6 +363,7 @@ struct device {
 
        struct kobject kobj;
        char    bus_id[BUS_ID_SIZE];    /* position on parent bus */
+       struct device_type      *type;
        unsigned                is_registered:1;
        struct device_attribute uevent_attr;
        struct device_attribute *devt_attr;
@@ -390,9 +399,10 @@ struct device {
 
        /* class_device migration path */
        struct list_head        node;
-       struct class            *class;         /* optional*/
+       struct class            *class;
        dev_t                   devt;           /* dev_t, creates the sysfs "dev" */
        struct attribute_group  **groups;       /* optional groups */
+       int                     uevent_suppress;
 
        void    (*release)(struct device * dev);
 };
index 8e4dbb5..50d568e 100644 (file)
@@ -1,10 +1,8 @@
+#ifndef __HID_DEBUG_H
+#define __HID_DEBUG_H
+
 /*
- * $Id: hid-debug.h,v 1.8 2001/09/25 09:37:57 vojtech Exp $
- *
- *  (c) 1999 Andreas Gal               <gal@cs.uni-magdeburg.de>
- *  (c) 2000-2001 Vojtech Pavlik       <vojtech@ucw.cz>
- *
- *  Some debug stuff for the HID parser.
+ *  Copyright (c) 2007 Jiri Kosina
  */
 
 /*
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
  */
 
-#include <linux/input.h>
-
-struct hid_usage_entry {
-       unsigned  page;
-       unsigned  usage;
-       char     *description;
-};
-
-static const struct hid_usage_entry hid_usage_table[] = {
-  {  0,      0, "Undefined" },
-  {  1,      0, "GenericDesktop" },
-    {0, 0x01, "Pointer"},
-    {0, 0x02, "Mouse"},
-    {0, 0x04, "Joystick"},
-    {0, 0x05, "GamePad"},
-    {0, 0x06, "Keyboard"},
-    {0, 0x07, "Keypad"},
-    {0, 0x08, "MultiAxis"},
-      {0, 0x30, "X"},
-      {0, 0x31, "Y"},
-      {0, 0x32, "Z"},
-      {0, 0x33, "Rx"},
-      {0, 0x34, "Ry"},
-      {0, 0x35, "Rz"},
-      {0, 0x36, "Slider"},
-      {0, 0x37, "Dial"},
-      {0, 0x38, "Wheel"},
-      {0, 0x39, "HatSwitch"},
-    {0, 0x3a, "CountedBuffer"},
-      {0, 0x3b, "ByteCount"},
-      {0, 0x3c, "MotionWakeup"},
-      {0, 0x3d, "Start"},
-      {0, 0x3e, "Select"},
-      {0, 0x40, "Vx"},
-      {0, 0x41, "Vy"},
-      {0, 0x42, "Vz"},
-      {0, 0x43, "Vbrx"},
-      {0, 0x44, "Vbry"},
-      {0, 0x45, "Vbrz"},
-      {0, 0x46, "Vno"},
-    {0, 0x80, "SystemControl"},
-      {0, 0x81, "SystemPowerDown"},
-      {0, 0x82, "SystemSleep"},
-      {0, 0x83, "SystemWakeUp"},
-      {0, 0x84, "SystemContextMenu"},
-      {0, 0x85, "SystemMainMenu"},
-      {0, 0x86, "SystemAppMenu"},
-      {0, 0x87, "SystemMenuHelp"},
-      {0, 0x88, "SystemMenuExit"},
-      {0, 0x89, "SystemMenuSelect"},
-      {0, 0x8a, "SystemMenuRight"},
-      {0, 0x8b, "SystemMenuLeft"},
-      {0, 0x8c, "SystemMenuUp"},
-      {0, 0x8d, "SystemMenuDown"},
-      {0, 0x90, "D-PadUp"},
-      {0, 0x91, "D-PadDown"},
-      {0, 0x92, "D-PadRight"},
-      {0, 0x93, "D-PadLeft"},
-  {  2, 0, "Simulation" },
-      {0, 0xb0, "Aileron"},
-      {0, 0xb1, "AileronTrim"},
-      {0, 0xb2, "Anti-Torque"},
-      {0, 0xb3, "Autopilot"},
-      {0, 0xb4, "Chaff"},
-      {0, 0xb5, "Collective"},
-      {0, 0xb6, "DiveBrake"},
-      {0, 0xb7, "ElectronicCountermeasures"},
-      {0, 0xb8, "Elevator"},
-      {0, 0xb9, "ElevatorTrim"},
-      {0, 0xba, "Rudder"},
-      {0, 0xbb, "Throttle"},
-      {0, 0xbc, "FlightCommunications"},
-      {0, 0xbd, "FlareRelease"},
-      {0, 0xbe, "LandingGear"},
-      {0, 0xbf, "ToeBrake"},
-  {  7, 0, "Keyboard" },
-  {  8, 0, "LED" },
-      {0, 0x01, "NumLock"},
-      {0, 0x02, "CapsLock"},
-      {0, 0x03, "ScrollLock"},
-      {0, 0x04, "Compose"},
-      {0, 0x05, "Kana"},
-      {0, 0x4b, "GenericIndicator"},
-  {  9, 0, "Button" },
-  { 10, 0, "Ordinal" },
-  { 12, 0, "Consumer" },
-      {0, 0x238, "HorizontalWheel"},
-  { 13, 0, "Digitizers" },
-    {0, 0x01, "Digitizer"},
-    {0, 0x02, "Pen"},
-    {0, 0x03, "LightPen"},
-    {0, 0x04, "TouchScreen"},
-    {0, 0x05, "TouchPad"},
-    {0, 0x20, "Stylus"},
-    {0, 0x21, "Puck"},
-    {0, 0x22, "Finger"},
-    {0, 0x30, "TipPressure"},
-    {0, 0x31, "BarrelPressure"},
-    {0, 0x32, "InRange"},
-    {0, 0x33, "Touch"},
-    {0, 0x34, "UnTouch"},
-    {0, 0x35, "Tap"},
-    {0, 0x39, "TabletFunctionKey"},
-    {0, 0x3a, "ProgramChangeKey"},
-    {0, 0x3c, "Invert"},
-    {0, 0x42, "TipSwitch"},
-    {0, 0x43, "SecondaryTipSwitch"},
-    {0, 0x44, "BarrelSwitch"},
-    {0, 0x45, "Eraser"},
-    {0, 0x46, "TabletPick"},
-  { 15, 0, "PhysicalInterfaceDevice" },
-    {0, 0x00, "Undefined"},
-    {0, 0x01, "Physical_Interface_Device"},
-      {0, 0x20, "Normal"},
-    {0, 0x21, "Set_Effect_Report"},
-      {0, 0x22, "Effect_Block_Index"},
-      {0, 0x23, "Parameter_Block_Offset"},
-      {0, 0x24, "ROM_Flag"},
-      {0, 0x25, "Effect_Type"},
-        {0, 0x26, "ET_Constant_Force"},
-        {0, 0x27, "ET_Ramp"},
-        {0, 0x28, "ET_Custom_Force_Data"},
-        {0, 0x30, "ET_Square"},
-        {0, 0x31, "ET_Sine"},
-        {0, 0x32, "ET_Triangle"},
-        {0, 0x33, "ET_Sawtooth_Up"},
-        {0, 0x34, "ET_Sawtooth_Down"},
-        {0, 0x40, "ET_Spring"},
-        {0, 0x41, "ET_Damper"},
-        {0, 0x42, "ET_Inertia"},
-        {0, 0x43, "ET_Friction"},
-      {0, 0x50, "Duration"},
-      {0, 0x51, "Sample_Period"},
-      {0, 0x52, "Gain"},
-      {0, 0x53, "Trigger_Button"},
-      {0, 0x54, "Trigger_Repeat_Interval"},
-      {0, 0x55, "Axes_Enable"},
-        {0, 0x56, "Direction_Enable"},
-      {0, 0x57, "Direction"},
-      {0, 0x58, "Type_Specific_Block_Offset"},
-        {0, 0x59, "Block_Type"},
-        {0, 0x5A, "Set_Envelope_Report"},
-          {0, 0x5B, "Attack_Level"},
-          {0, 0x5C, "Attack_Time"},
-          {0, 0x5D, "Fade_Level"},
-          {0, 0x5E, "Fade_Time"},
-        {0, 0x5F, "Set_Condition_Report"},
-        {0, 0x60, "CP_Offset"},
-        {0, 0x61, "Positive_Coefficient"},
-        {0, 0x62, "Negative_Coefficient"},
-        {0, 0x63, "Positive_Saturation"},
-        {0, 0x64, "Negative_Saturation"},
-        {0, 0x65, "Dead_Band"},
-      {0, 0x66, "Download_Force_Sample"},
-      {0, 0x67, "Isoch_Custom_Force_Enable"},
-      {0, 0x68, "Custom_Force_Data_Report"},
-        {0, 0x69, "Custom_Force_Data"},
-        {0, 0x6A, "Custom_Force_Vendor_Defined_Data"},
-      {0, 0x6B, "Set_Custom_Force_Report"},
-        {0, 0x6C, "Custom_Force_Data_Offset"},
-        {0, 0x6D, "Sample_Count"},
-      {0, 0x6E, "Set_Periodic_Report"},
-        {0, 0x6F, "Offset"},
-        {0, 0x70, "Magnitude"},
-        {0, 0x71, "Phase"},
-        {0, 0x72, "Period"},
-      {0, 0x73, "Set_Constant_Force_Report"},
-        {0, 0x74, "Set_Ramp_Force_Report"},
-        {0, 0x75, "Ramp_Start"},
-        {0, 0x76, "Ramp_End"},
-      {0, 0x77, "Effect_Operation_Report"},
-        {0, 0x78, "Effect_Operation"},
-          {0, 0x79, "Op_Effect_Start"},
-          {0, 0x7A, "Op_Effect_Start_Solo"},
-          {0, 0x7B, "Op_Effect_Stop"},
-          {0, 0x7C, "Loop_Count"},
-      {0, 0x7D, "Device_Gain_Report"},
-        {0, 0x7E, "Device_Gain"},
-    {0, 0x7F, "PID_Pool_Report"},
-      {0, 0x80, "RAM_Pool_Size"},
-      {0, 0x81, "ROM_Pool_Size"},
-      {0, 0x82, "ROM_Effect_Block_Count"},
-      {0, 0x83, "Simultaneous_Effects_Max"},
-      {0, 0x84, "Pool_Alignment"},
-    {0, 0x85, "PID_Pool_Move_Report"},
-      {0, 0x86, "Move_Source"},
-      {0, 0x87, "Move_Destination"},
-      {0, 0x88, "Move_Length"},
-    {0, 0x89, "PID_Block_Load_Report"},
-      {0, 0x8B, "Block_Load_Status"},
-      {0, 0x8C, "Block_Load_Success"},
-      {0, 0x8D, "Block_Load_Full"},
-      {0, 0x8E, "Block_Load_Error"},
-      {0, 0x8F, "Block_Handle"},
-      {0, 0x90, "PID_Block_Free_Report"},
-      {0, 0x91, "Type_Specific_Block_Handle"},
-    {0, 0x92, "PID_State_Report"},
-      {0, 0x94, "Effect_Playing"},
-      {0, 0x95, "PID_Device_Control_Report"},
-        {0, 0x96, "PID_Device_Control"},
-        {0, 0x97, "DC_Enable_Actuators"},
-        {0, 0x98, "DC_Disable_Actuators"},
-        {0, 0x99, "DC_Stop_All_Effects"},
-        {0, 0x9A, "DC_Device_Reset"},
-        {0, 0x9B, "DC_Device_Pause"},
-        {0, 0x9C, "DC_Device_Continue"},
-      {0, 0x9F, "Device_Paused"},
-      {0, 0xA0, "Actuators_Enabled"},
-      {0, 0xA4, "Safety_Switch"},
-      {0, 0xA5, "Actuator_Override_Switch"},
-      {0, 0xA6, "Actuator_Power"},
-    {0, 0xA7, "Start_Delay"},
-    {0, 0xA8, "Parameter_Block_Size"},
-    {0, 0xA9, "Device_Managed_Pool"},
-    {0, 0xAA, "Shared_Parameter_Blocks"},
-    {0, 0xAB, "Create_New_Effect_Report"},
-    {0, 0xAC, "RAM_Pool_Available"},
-  { 0x84, 0, "Power Device" },
-    { 0x84, 0x02, "PresentStatus" },
-    { 0x84, 0x03, "ChangeStatus" },
-    { 0x84, 0x04, "UPS" },
-    { 0x84, 0x05, "PowerSupply" },
-    { 0x84, 0x10, "BatterySystem" },
-    { 0x84, 0x11, "BatterySystemID" },
-    { 0x84, 0x12, "Battery" },
-    { 0x84, 0x13, "BatteryID" },
-    { 0x84, 0x14, "Charger" },
-    { 0x84, 0x15, "ChargerID" },
-    { 0x84, 0x16, "PowerConverter" },
-    { 0x84, 0x17, "PowerConverterID" },
-    { 0x84, 0x18, "OutletSystem" },
-    { 0x84, 0x19, "OutletSystemID" },
-    { 0x84, 0x1a, "Input" },
-    { 0x84, 0x1b, "InputID" },
-    { 0x84, 0x1c, "Output" },
-    { 0x84, 0x1d, "OutputID" },
-    { 0x84, 0x1e, "Flow" },
-    { 0x84, 0x1f, "FlowID" },
-    { 0x84, 0x20, "Outlet" },
-    { 0x84, 0x21, "OutletID" },
-    { 0x84, 0x22, "Gang" },
-    { 0x84, 0x24, "PowerSummary" },
-    { 0x84, 0x25, "PowerSummaryID" },
-    { 0x84, 0x30, "Voltage" },
-    { 0x84, 0x31, "Current" },
-    { 0x84, 0x32, "Frequency" },
-    { 0x84, 0x33, "ApparentPower" },
-    { 0x84, 0x35, "PercentLoad" },
-    { 0x84, 0x40, "ConfigVoltage" },
-    { 0x84, 0x41, "ConfigCurrent" },
-    { 0x84, 0x43, "ConfigApparentPower" },
-    { 0x84, 0x53, "LowVoltageTransfer" },
-    { 0x84, 0x54, "HighVoltageTransfer" },
-    { 0x84, 0x56, "DelayBeforeStartup" },
-    { 0x84, 0x57, "DelayBeforeShutdown" },
-    { 0x84, 0x58, "Test" },
-    { 0x84, 0x5a, "AudibleAlarmControl" },
-    { 0x84, 0x60, "Present" },
-    { 0x84, 0x61, "Good" },
-    { 0x84, 0x62, "InternalFailure" },
-    { 0x84, 0x65, "Overload" },
-    { 0x84, 0x66, "OverCharged" },
-    { 0x84, 0x67, "OverTemperature" },
-    { 0x84, 0x68, "ShutdownRequested" },
-    { 0x84, 0x69, "ShutdownImminent" },
-    { 0x84, 0x6b, "SwitchOn/Off" },
-    { 0x84, 0x6c, "Switchable" },
-    { 0x84, 0x6d, "Used" },
-    { 0x84, 0x6e, "Boost" },
-    { 0x84, 0x73, "CommunicationLost" },
-    { 0x84, 0xfd, "iManufacturer" },
-    { 0x84, 0xfe, "iProduct" },
-    { 0x84, 0xff, "iSerialNumber" },
-  { 0x85, 0, "Battery System" },
-    { 0x85, 0x01, "SMBBatteryMode" },
-    { 0x85, 0x02, "SMBBatteryStatus" },
-    { 0x85, 0x03, "SMBAlarmWarning" },
-    { 0x85, 0x04, "SMBChargerMode" },
-    { 0x85, 0x05, "SMBChargerStatus" },
-    { 0x85, 0x06, "SMBChargerSpecInfo" },
-    { 0x85, 0x07, "SMBSelectorState" },
-    { 0x85, 0x08, "SMBSelectorPresets" },
-    { 0x85, 0x09, "SMBSelectorInfo" },
-    { 0x85, 0x29, "RemainingCapacityLimit" },
-    { 0x85, 0x2c, "CapacityMode" },
-    { 0x85, 0x42, "BelowRemainingCapacityLimit" },
-    { 0x85, 0x44, "Charging" },
-    { 0x85, 0x45, "Discharging" },
-    { 0x85, 0x4b, "NeedReplacement" },
-    { 0x85, 0x66, "RemainingCapacity" },
-    { 0x85, 0x68, "RunTimeToEmpty" },
-    { 0x85, 0x6a, "AverageTimeToFull" },
-    { 0x85, 0x83, "DesignCapacity" },
-    { 0x85, 0x85, "ManufacturerDate" },
-    { 0x85, 0x89, "iDeviceChemistry" },
-    { 0x85, 0x8b, "Rechargable" },
-    { 0x85, 0x8f, "iOEMInformation" },
-    { 0x85, 0x8d, "CapacityGranularity1" },
-    { 0x85, 0xd0, "ACPresent" },
-  /* pages 0xff00 to 0xffff are vendor-specific */
-  { 0xffff, 0, "Vendor-specific-FF" },
-  { 0, 0, NULL }
-};
-
-static void resolv_usage_page(unsigned page) {
-       const struct hid_usage_entry *p;
-
-       for (p = hid_usage_table; p->description; p++)
-               if (p->page == page) {
-                       printk("%s", p->description);
-                       return;
-               }
-       printk("%04x", page);
-}
-
-static void resolv_usage(unsigned usage) {
-       const struct hid_usage_entry *p;
-
-       resolv_usage_page(usage >> 16);
-       printk(".");
-       for (p = hid_usage_table; p->description; p++)
-               if (p->page == (usage >> 16)) {
-                       for(++p; p->description && p->usage != 0; p++)
-                               if (p->usage == (usage & 0xffff)) {
-                                       printk("%s", p->description);
-                                       return;
-                               }
-                       break;
-               }
-       printk("%04x", usage & 0xffff);
-}
-
-__inline__ static void tab(int n) {
-       while (n--) printk(" ");
-}
-
-static void hid_dump_field(struct hid_field *field, int n) {
-       int j;
-
-       if (field->physical) {
-               tab(n);
-               printk("Physical(");
-               resolv_usage(field->physical); printk(")\n");
-       }
-       if (field->logical) {
-               tab(n);
-               printk("Logical(");
-               resolv_usage(field->logical); printk(")\n");
-       }
-       tab(n); printk("Usage(%d)\n", field->maxusage);
-       for (j = 0; j < field->maxusage; j++) {
-               tab(n+2);resolv_usage(field->usage[j].hid); printk("\n");
-       }
-       if (field->logical_minimum != field->logical_maximum) {
-               tab(n); printk("Logical Minimum(%d)\n", field->logical_minimum);
-               tab(n); printk("Logical Maximum(%d)\n", field->logical_maximum);
-       }
-       if (field->physical_minimum != field->physical_maximum) {
-               tab(n); printk("Physical Minimum(%d)\n", field->physical_minimum);
-               tab(n); printk("Physical Maximum(%d)\n", field->physical_maximum);
-       }
-       if (field->unit_exponent) {
-               tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent);
-       }
-       if (field->unit) {
-               char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" };
-               char *units[5][8] = {
-                       { "None", "None", "None", "None", "None", "None", "None", "None" },
-                       { "None", "Centimeter", "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
-                       { "None", "Radians",    "Gram", "Seconds", "Kelvin",     "Ampere", "Candela", "None" },
-                       { "None", "Inch",       "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" },
-                       { "None", "Degrees",    "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }
-               };
-
-               int i;
-               int sys;
-                __u32 data = field->unit;
-
-               /* First nibble tells us which system we're in. */
-               sys = data & 0xf;
-               data >>= 4;
-
-               if(sys > 4) {
-                       tab(n); printk("Unit(Invalid)\n");
-               }
-               else {
-                       int earlier_unit = 0;
-
-                       tab(n); printk("Unit(%s : ", systems[sys]);
-
-                       for (i=1 ; i<sizeof(__u32)*2 ; i++) {
-                               char nibble = data & 0xf;
-                               data >>= 4;
-                               if (nibble != 0) {
-                                       if(earlier_unit++ > 0)
-                                               printk("*");
-                                       printk("%s", units[sys][i]);
-                                       if(nibble != 1) {
-                                               /* This is a _signed_ nibble(!) */
-
-                                               int val = nibble & 0x7;
-                                               if(nibble & 0x08)
-                                                       val = -((0x7 & ~val) +1);
-                                               printk("^%d", val);
-                                       }
-                               }
-                       }
-                       printk(")\n");
-               }
-       }
-       tab(n); printk("Report Size(%u)\n", field->report_size);
-       tab(n); printk("Report Count(%u)\n", field->report_count);
-       tab(n); printk("Report Offset(%u)\n", field->report_offset);
-
-       tab(n); printk("Flags( ");
-       j = field->flags;
-       printk("%s", HID_MAIN_ITEM_CONSTANT & j ? "Constant " : "");
-       printk("%s", HID_MAIN_ITEM_VARIABLE & j ? "Variable " : "Array ");
-       printk("%s", HID_MAIN_ITEM_RELATIVE & j ? "Relative " : "Absolute ");
-       printk("%s", HID_MAIN_ITEM_WRAP & j ? "Wrap " : "");
-       printk("%s", HID_MAIN_ITEM_NONLINEAR & j ? "NonLinear " : "");
-       printk("%s", HID_MAIN_ITEM_NO_PREFERRED & j ? "NoPrefferedState " : "");
-       printk("%s", HID_MAIN_ITEM_NULL_STATE & j ? "NullState " : "");
-       printk("%s", HID_MAIN_ITEM_VOLATILE & j ? "Volatile " : "");
-       printk("%s", HID_MAIN_ITEM_BUFFERED_BYTE & j ? "BufferedByte " : "");
-       printk(")\n");
-}
-
-static void __attribute__((unused)) hid_dump_device(struct hid_device *device) {
-       struct hid_report_enum *report_enum;
-       struct hid_report *report;
-       struct list_head *list;
-       unsigned i,k;
-       static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
-
-       for (i = 0; i < HID_REPORT_TYPES; i++) {
-               report_enum = device->report_enum + i;
-               list = report_enum->report_list.next;
-               while (list != &report_enum->report_list) {
-                       report = (struct hid_report *) list;
-                       tab(2);
-                       printk("%s", table[i]);
-                       if (report->id)
-                               printk("(%d)", report->id);
-                       printk("[%s]", table[report->type]);
-                       printk("\n");
-                       for (k = 0; k < report->maxfield; k++) {
-                               tab(4);
-                               printk("Field(%d)\n", k);
-                               hid_dump_field(report->field[k], 6);
-                       }
-                       list = list->next;
-               }
-       }
-}
-
-static void __attribute__((unused)) hid_dump_input(struct hid_usage *usage, __s32 value) {
-       printk("hid-debug: input ");
-       resolv_usage(usage->hid);
-       printk(" = %d\n", value);
-}
-
-
-static char *events[EV_MAX + 1] = {
-       [EV_SYN] = "Sync",                      [EV_KEY] = "Key",
-       [EV_REL] = "Relative",                  [EV_ABS] = "Absolute",
-       [EV_MSC] = "Misc",                      [EV_LED] = "LED",
-       [EV_SND] = "Sound",                     [EV_REP] = "Repeat",
-       [EV_FF] = "ForceFeedback",              [EV_PWR] = "Power",
-       [EV_FF_STATUS] = "ForceFeedbackStatus",
-};
-
-static char *syncs[2] = {
-       [SYN_REPORT] = "Report",                [SYN_CONFIG] = "Config",
-};
-static char *keys[KEY_MAX + 1] = {
-       [KEY_RESERVED] = "Reserved",            [KEY_ESC] = "Esc",
-       [KEY_1] = "1",                          [KEY_2] = "2",
-       [KEY_3] = "3",                          [KEY_4] = "4",
-       [KEY_5] = "5",                          [KEY_6] = "6",
-       [KEY_7] = "7",                          [KEY_8] = "8",
-       [KEY_9] = "9",                          [KEY_0] = "0",
-       [KEY_MINUS] = "Minus",                  [KEY_EQUAL] = "Equal",
-       [KEY_BACKSPACE] = "Backspace",          [KEY_TAB] = "Tab",
-       [KEY_Q] = "Q",                          [KEY_W] = "W",
-       [KEY_E] = "E",                          [KEY_R] = "R",
-       [KEY_T] = "T",                          [KEY_Y] = "Y",
-       [KEY_U] = "U",                          [KEY_I] = "I",
-       [KEY_O] = "O",                          [KEY_P] = "P",
-       [KEY_LEFTBRACE] = "LeftBrace",          [KEY_RIGHTBRACE] = "RightBrace",
-       [KEY_ENTER] = "Enter",                  [KEY_LEFTCTRL] = "LeftControl",
-       [KEY_A] = "A",                          [KEY_S] = "S",
-       [KEY_D] = "D",                          [KEY_F] = "F",
-       [KEY_G] = "G",                          [KEY_H] = "H",
-       [KEY_J] = "J",                          [KEY_K] = "K",
-       [KEY_L] = "L",                          [KEY_SEMICOLON] = "Semicolon",
-       [KEY_APOSTROPHE] = "Apostrophe",        [KEY_GRAVE] = "Grave",
-       [KEY_LEFTSHIFT] = "LeftShift",          [KEY_BACKSLASH] = "BackSlash",
-       [KEY_Z] = "Z",                          [KEY_X] = "X",
-       [KEY_C] = "C",                          [KEY_V] = "V",
-       [KEY_B] = "B",                          [KEY_N] = "N",
-       [KEY_M] = "M",                          [KEY_COMMA] = "Comma",
-       [KEY_DOT] = "Dot",                      [KEY_SLASH] = "Slash",
-       [KEY_RIGHTSHIFT] = "RightShift",        [KEY_KPASTERISK] = "KPAsterisk",
-       [KEY_LEFTALT] = "LeftAlt",              [KEY_SPACE] = "Space",
-       [KEY_CAPSLOCK] = "CapsLock",            [KEY_F1] = "F1",
-       [KEY_F2] = "F2",                        [KEY_F3] = "F3",
-       [KEY_F4] = "F4",                        [KEY_F5] = "F5",
-       [KEY_F6] = "F6",                        [KEY_F7] = "F7",
-       [KEY_F8] = "F8",                        [KEY_F9] = "F9",
-       [KEY_F10] = "F10",                      [KEY_NUMLOCK] = "NumLock",
-       [KEY_SCROLLLOCK] = "ScrollLock",        [KEY_KP7] = "KP7",
-       [KEY_KP8] = "KP8",                      [KEY_KP9] = "KP9",
-       [KEY_KPMINUS] = "KPMinus",              [KEY_KP4] = "KP4",
-       [KEY_KP5] = "KP5",                      [KEY_KP6] = "KP6",
-       [KEY_KPPLUS] = "KPPlus",                [KEY_KP1] = "KP1",
-       [KEY_KP2] = "KP2",                      [KEY_KP3] = "KP3",
-       [KEY_KP0] = "KP0",                      [KEY_KPDOT] = "KPDot",
-       [KEY_ZENKAKUHANKAKU] = "Zenkaku/Hankaku", [KEY_102ND] = "102nd",
-       [KEY_F11] = "F11",                      [KEY_F12] = "F12",
-       [KEY_RO] = "RO",                        [KEY_KATAKANA] = "Katakana",
-       [KEY_HIRAGANA] = "HIRAGANA",            [KEY_HENKAN] = "Henkan",
-       [KEY_KATAKANAHIRAGANA] = "Katakana/Hiragana", [KEY_MUHENKAN] = "Muhenkan",
-       [KEY_KPJPCOMMA] = "KPJpComma",          [KEY_KPENTER] = "KPEnter",
-       [KEY_RIGHTCTRL] = "RightCtrl",          [KEY_KPSLASH] = "KPSlash",
-       [KEY_SYSRQ] = "SysRq",                  [KEY_RIGHTALT] = "RightAlt",
-       [KEY_LINEFEED] = "LineFeed",            [KEY_HOME] = "Home",
-       [KEY_UP] = "Up",                        [KEY_PAGEUP] = "PageUp",
-       [KEY_LEFT] = "Left",                    [KEY_RIGHT] = "Right",
-       [KEY_END] = "End",                      [KEY_DOWN] = "Down",
-       [KEY_PAGEDOWN] = "PageDown",            [KEY_INSERT] = "Insert",
-       [KEY_DELETE] = "Delete",                [KEY_MACRO] = "Macro",
-       [KEY_MUTE] = "Mute",                    [KEY_VOLUMEDOWN] = "VolumeDown",
-       [KEY_VOLUMEUP] = "VolumeUp",            [KEY_POWER] = "Power",
-       [KEY_KPEQUAL] = "KPEqual",              [KEY_KPPLUSMINUS] = "KPPlusMinus",
-       [KEY_PAUSE] = "Pause",                  [KEY_KPCOMMA] = "KPComma",
-       [KEY_HANGUEL] = "Hangeul",              [KEY_HANJA] = "Hanja",
-       [KEY_YEN] = "Yen",                      [KEY_LEFTMETA] = "LeftMeta",
-       [KEY_RIGHTMETA] = "RightMeta",          [KEY_COMPOSE] = "Compose",
-       [KEY_STOP] = "Stop",                    [KEY_AGAIN] = "Again",
-       [KEY_PROPS] = "Props",                  [KEY_UNDO] = "Undo",
-       [KEY_FRONT] = "Front",                  [KEY_COPY] = "Copy",
-       [KEY_OPEN] = "Open",                    [KEY_PASTE] = "Paste",
-       [KEY_FIND] = "Find",                    [KEY_CUT] = "Cut",
-       [KEY_HELP] = "Help",                    [KEY_MENU] = "Menu",
-       [KEY_CALC] = "Calc",                    [KEY_SETUP] = "Setup",
-       [KEY_SLEEP] = "Sleep",                  [KEY_WAKEUP] = "WakeUp",
-       [KEY_FILE] = "File",                    [KEY_SENDFILE] = "SendFile",
-       [KEY_DELETEFILE] = "DeleteFile",        [KEY_XFER] = "X-fer",
-       [KEY_PROG1] = "Prog1",                  [KEY_PROG2] = "Prog2",
-       [KEY_WWW] = "WWW",                      [KEY_MSDOS] = "MSDOS",
-       [KEY_COFFEE] = "Coffee",                [KEY_DIRECTION] = "Direction",
-       [KEY_CYCLEWINDOWS] = "CycleWindows",    [KEY_MAIL] = "Mail",
-       [KEY_BOOKMARKS] = "Bookmarks",          [KEY_COMPUTER] = "Computer",
-       [KEY_BACK] = "Back",                    [KEY_FORWARD] = "Forward",
-       [KEY_CLOSECD] = "CloseCD",              [KEY_EJECTCD] = "EjectCD",
-       [KEY_EJECTCLOSECD] = "EjectCloseCD",    [KEY_NEXTSONG] = "NextSong",
-       [KEY_PLAYPAUSE] = "PlayPause",          [KEY_PREVIOUSSONG] = "PreviousSong",
-       [KEY_STOPCD] = "StopCD",                [KEY_RECORD] = "Record",
-       [KEY_REWIND] = "Rewind",                [KEY_PHONE] = "Phone",
-       [KEY_ISO] = "ISOKey",                   [KEY_CONFIG] = "Config",
-       [KEY_HOMEPAGE] = "HomePage",            [KEY_REFRESH] = "Refresh",
-       [KEY_EXIT] = "Exit",                    [KEY_MOVE] = "Move",
-       [KEY_EDIT] = "Edit",                    [KEY_SCROLLUP] = "ScrollUp",
-       [KEY_SCROLLDOWN] = "ScrollDown",        [KEY_KPLEFTPAREN] = "KPLeftParenthesis",
-       [KEY_KPRIGHTPAREN] = "KPRightParenthesis", [KEY_NEW] = "New",
-       [KEY_REDO] = "Redo",                    [KEY_F13] = "F13",
-       [KEY_F14] = "F14",                      [KEY_F15] = "F15",
-       [KEY_F16] = "F16",                      [KEY_F17] = "F17",
-       [KEY_F18] = "F18",                      [KEY_F19] = "F19",
-       [KEY_F20] = "F20",                      [KEY_F21] = "F21",
-       [KEY_F22] = "F22",                      [KEY_F23] = "F23",
-       [KEY_F24] = "F24",                      [KEY_PLAYCD] = "PlayCD",
-       [KEY_PAUSECD] = "PauseCD",              [KEY_PROG3] = "Prog3",
-       [KEY_PROG4] = "Prog4",                  [KEY_SUSPEND] = "Suspend",
-       [KEY_CLOSE] = "Close",                  [KEY_PLAY] = "Play",
-       [KEY_FASTFORWARD] = "FastForward",      [KEY_BASSBOOST] = "BassBoost",
-       [KEY_PRINT] = "Print",                  [KEY_HP] = "HP",
-       [KEY_CAMERA] = "Camera",                [KEY_SOUND] = "Sound",
-       [KEY_QUESTION] = "Question",            [KEY_EMAIL] = "Email",
-       [KEY_CHAT] = "Chat",                    [KEY_SEARCH] = "Search",
-       [KEY_CONNECT] = "Connect",              [KEY_FINANCE] = "Finance",
-       [KEY_SPORT] = "Sport",                  [KEY_SHOP] = "Shop",
-       [KEY_ALTERASE] = "AlternateErase",      [KEY_CANCEL] = "Cancel",
-       [KEY_BRIGHTNESSDOWN] = "BrightnessDown", [KEY_BRIGHTNESSUP] = "BrightnessUp",
-       [KEY_MEDIA] = "Media",                  [KEY_UNKNOWN] = "Unknown",
-       [BTN_0] = "Btn0",                       [BTN_1] = "Btn1",
-       [BTN_2] = "Btn2",                       [BTN_3] = "Btn3",
-       [BTN_4] = "Btn4",                       [BTN_5] = "Btn5",
-       [BTN_6] = "Btn6",                       [BTN_7] = "Btn7",
-       [BTN_8] = "Btn8",                       [BTN_9] = "Btn9",
-       [BTN_LEFT] = "LeftBtn",                 [BTN_RIGHT] = "RightBtn",
-       [BTN_MIDDLE] = "MiddleBtn",             [BTN_SIDE] = "SideBtn",
-       [BTN_EXTRA] = "ExtraBtn",               [BTN_FORWARD] = "ForwardBtn",
-       [BTN_BACK] = "BackBtn",                 [BTN_TASK] = "TaskBtn",
-       [BTN_TRIGGER] = "Trigger",              [BTN_THUMB] = "ThumbBtn",
-       [BTN_THUMB2] = "ThumbBtn2",             [BTN_TOP] = "TopBtn",
-       [BTN_TOP2] = "TopBtn2",                 [BTN_PINKIE] = "PinkieBtn",
-       [BTN_BASE] = "BaseBtn",                 [BTN_BASE2] = "BaseBtn2",
-       [BTN_BASE3] = "BaseBtn3",               [BTN_BASE4] = "BaseBtn4",
-       [BTN_BASE5] = "BaseBtn5",               [BTN_BASE6] = "BaseBtn6",
-       [BTN_DEAD] = "BtnDead",                 [BTN_A] = "BtnA",
-       [BTN_B] = "BtnB",                       [BTN_C] = "BtnC",
-       [BTN_X] = "BtnX",                       [BTN_Y] = "BtnY",
-       [BTN_Z] = "BtnZ",                       [BTN_TL] = "BtnTL",
-       [BTN_TR] = "BtnTR",                     [BTN_TL2] = "BtnTL2",
-       [BTN_TR2] = "BtnTR2",                   [BTN_SELECT] = "BtnSelect",
-       [BTN_START] = "BtnStart",               [BTN_MODE] = "BtnMode",
-       [BTN_THUMBL] = "BtnThumbL",             [BTN_THUMBR] = "BtnThumbR",
-       [BTN_TOOL_PEN] = "ToolPen",             [BTN_TOOL_RUBBER] = "ToolRubber",
-       [BTN_TOOL_BRUSH] = "ToolBrush",         [BTN_TOOL_PENCIL] = "ToolPencil",
-       [BTN_TOOL_AIRBRUSH] = "ToolAirbrush",   [BTN_TOOL_FINGER] = "ToolFinger",
-       [BTN_TOOL_MOUSE] = "ToolMouse",         [BTN_TOOL_LENS] = "ToolLens",
-       [BTN_TOUCH] = "Touch",                  [BTN_STYLUS] = "Stylus",
-       [BTN_STYLUS2] = "Stylus2",              [BTN_TOOL_DOUBLETAP] = "ToolDoubleTap",
-       [BTN_TOOL_TRIPLETAP] = "ToolTripleTap", [BTN_GEAR_DOWN] = "WheelBtn",
-       [BTN_GEAR_UP] = "Gear up",              [KEY_OK] = "Ok",
-       [KEY_SELECT] = "Select",                [KEY_GOTO] = "Goto",
-       [KEY_CLEAR] = "Clear",                  [KEY_POWER2] = "Power2",
-       [KEY_OPTION] = "Option",                [KEY_INFO] = "Info",
-       [KEY_TIME] = "Time",                    [KEY_VENDOR] = "Vendor",
-       [KEY_ARCHIVE] = "Archive",              [KEY_PROGRAM] = "Program",
-       [KEY_CHANNEL] = "Channel",              [KEY_FAVORITES] = "Favorites",
-       [KEY_EPG] = "EPG",                      [KEY_PVR] = "PVR",
-       [KEY_MHP] = "MHP",                      [KEY_LANGUAGE] = "Language",
-       [KEY_TITLE] = "Title",                  [KEY_SUBTITLE] = "Subtitle",
-       [KEY_ANGLE] = "Angle",                  [KEY_ZOOM] = "Zoom",
-       [KEY_MODE] = "Mode",                    [KEY_KEYBOARD] = "Keyboard",
-       [KEY_SCREEN] = "Screen",                [KEY_PC] = "PC",
-       [KEY_TV] = "TV",                        [KEY_TV2] = "TV2",
-       [KEY_VCR] = "VCR",                      [KEY_VCR2] = "VCR2",
-       [KEY_SAT] = "Sat",                      [KEY_SAT2] = "Sat2",
-       [KEY_CD] = "CD",                        [KEY_TAPE] = "Tape",
-       [KEY_RADIO] = "Radio",                  [KEY_TUNER] = "Tuner",
-       [KEY_PLAYER] = "Player",                [KEY_TEXT] = "Text",
-       [KEY_DVD] = "DVD",                      [KEY_AUX] = "Aux",
-       [KEY_MP3] = "MP3",                      [KEY_AUDIO] = "Audio",
-       [KEY_VIDEO] = "Video",                  [KEY_DIRECTORY] = "Directory",
-       [KEY_LIST] = "List",                    [KEY_MEMO] = "Memo",
-       [KEY_CALENDAR] = "Calendar",            [KEY_RED] = "Red",
-       [KEY_GREEN] = "Green",                  [KEY_YELLOW] = "Yellow",
-       [KEY_BLUE] = "Blue",                    [KEY_CHANNELUP] = "ChannelUp",
-       [KEY_CHANNELDOWN] = "ChannelDown",      [KEY_FIRST] = "First",
-       [KEY_LAST] = "Last",                    [KEY_AB] = "AB",
-       [KEY_NEXT] = "Next",                    [KEY_RESTART] = "Restart",
-       [KEY_SLOW] = "Slow",                    [KEY_SHUFFLE] = "Shuffle",
-       [KEY_BREAK] = "Break",                  [KEY_PREVIOUS] = "Previous",
-       [KEY_DIGITS] = "Digits",                [KEY_TEEN] = "TEEN",
-       [KEY_TWEN] = "TWEN",                    [KEY_DEL_EOL] = "DeleteEOL",
-       [KEY_DEL_EOS] = "DeleteEOS",            [KEY_INS_LINE] = "InsertLine",
-       [KEY_DEL_LINE] = "DeleteLine",
-       [KEY_SEND] = "Send",                    [KEY_REPLY] = "Reply",
-       [KEY_FORWARDMAIL] = "ForwardMail",      [KEY_SAVE] = "Save",
-       [KEY_DOCUMENTS] = "Documents",
-       [KEY_FN] = "Fn",                        [KEY_FN_ESC] = "Fn+ESC",
-       [KEY_FN_1] = "Fn+1",                    [KEY_FN_2] = "Fn+2",
-       [KEY_FN_B] = "Fn+B",                    [KEY_FN_D] = "Fn+D",
-       [KEY_FN_E] = "Fn+E",                    [KEY_FN_F] = "Fn+F",
-       [KEY_FN_S] = "Fn+S",
-       [KEY_FN_F1] = "Fn+F1",                  [KEY_FN_F2] = "Fn+F2",
-       [KEY_FN_F3] = "Fn+F3",                  [KEY_FN_F4] = "Fn+F4",
-       [KEY_FN_F5] = "Fn+F5",                  [KEY_FN_F6] = "Fn+F6",
-       [KEY_FN_F7] = "Fn+F7",                  [KEY_FN_F8] = "Fn+F8",
-       [KEY_FN_F9] = "Fn+F9",                  [KEY_FN_F10] = "Fn+F10",
-       [KEY_FN_F11] = "Fn+F11",                [KEY_FN_F12] = "Fn+F12",
-       [KEY_KBDILLUMTOGGLE] = "KbdIlluminationToggle",
-       [KEY_KBDILLUMDOWN] = "KbdIlluminationDown",
-       [KEY_KBDILLUMUP] = "KbdIlluminationUp",
-       [KEY_SWITCHVIDEOMODE] = "SwitchVideoMode",
-};
-
-static char *relatives[REL_MAX + 1] = {
-       [REL_X] = "X",                  [REL_Y] = "Y",
-       [REL_Z] = "Z",                  [REL_RX] = "Rx",
-       [REL_RY] = "Ry",                [REL_RZ] = "Rz",
-       [REL_HWHEEL] = "HWheel",        [REL_DIAL] = "Dial",
-       [REL_WHEEL] = "Wheel",          [REL_MISC] = "Misc",
-};
-
-static char *absolutes[ABS_MAX + 1] = {
-       [ABS_X] = "X",                  [ABS_Y] = "Y",
-       [ABS_Z] = "Z",                  [ABS_RX] = "Rx",
-       [ABS_RY] = "Ry",                [ABS_RZ] = "Rz",
-       [ABS_THROTTLE] = "Throttle",    [ABS_RUDDER] = "Rudder",
-       [ABS_WHEEL] = "Wheel",          [ABS_GAS] = "Gas",
-       [ABS_BRAKE] = "Brake",          [ABS_HAT0X] = "Hat0X",
-       [ABS_HAT0Y] = "Hat0Y",          [ABS_HAT1X] = "Hat1X",
-       [ABS_HAT1Y] = "Hat1Y",          [ABS_HAT2X] = "Hat2X",
-       [ABS_HAT2Y] = "Hat2Y",          [ABS_HAT3X] = "Hat3X",
-       [ABS_HAT3Y] = "Hat 3Y",         [ABS_PRESSURE] = "Pressure",
-       [ABS_DISTANCE] = "Distance",    [ABS_TILT_X] = "XTilt",
-       [ABS_TILT_Y] = "YTilt",         [ABS_TOOL_WIDTH] = "Tool Width",
-       [ABS_VOLUME] = "Volume",        [ABS_MISC] = "Misc",
-};
+#ifdef CONFIG_HID_DEBUG
 
-static char *misc[MSC_MAX + 1] = {
-       [MSC_SERIAL] = "Serial",        [MSC_PULSELED] = "Pulseled",
-       [MSC_GESTURE] = "Gesture",      [MSC_RAW] = "RawData"
-};
+void hid_dump_input(struct hid_usage *, __s32);
+void hid_dump_device(struct hid_device *);
+void hid_dump_field(struct hid_field *, int);
+void hid_resolv_usage(unsigned);
+void hid_resolv_event(__u8, __u16);
 
-static char *leds[LED_MAX + 1] = {
-       [LED_NUML] = "NumLock",         [LED_CAPSL] = "CapsLock",
-       [LED_SCROLLL] = "ScrollLock",   [LED_COMPOSE] = "Compose",
-       [LED_KANA] = "Kana",            [LED_SLEEP] = "Sleep",
-       [LED_SUSPEND] = "Suspend",      [LED_MUTE] = "Mute",
-       [LED_MISC] = "Misc",
-};
+#else
 
-static char *repeats[REP_MAX + 1] = {
-       [REP_DELAY] = "Delay",          [REP_PERIOD] = "Period"
-};
+#define hid_dump_input(a,b)     do { } while (0)
+#define hid_dump_device(c)      do { } while (0)
+#define hid_dump_field(a,b)     do { } while (0)
+#define hid_resolv_usage(a)         do { } while (0)
+#define hid_resolv_event(a,b)       do { } while (0)
 
-static char *sounds[SND_MAX + 1] = {
-       [SND_CLICK] = "Click",          [SND_BELL] = "Bell",
-       [SND_TONE] = "Tone"
-};
+#endif /* CONFIG_HID_DEBUG */
 
-static char **names[EV_MAX + 1] = {
-       [EV_SYN] = syncs,                       [EV_KEY] = keys,
-       [EV_REL] = relatives,                   [EV_ABS] = absolutes,
-       [EV_MSC] = misc,                        [EV_LED] = leds,
-       [EV_SND] = sounds,                      [EV_REP] = repeats,
-};
 
-static void __attribute__((unused)) resolv_event(__u8 type, __u16 code) {
+#endif
 
-       printk("%s.%s", events[type] ? events[type] : "?",
-               names[type] ? (names[type][code] ? names[type][code] : "?") : "?");
-}
index 342b4e6..d26b08f 100644 (file)
@@ -264,6 +264,9 @@ struct hid_item {
 #define HID_QUIRK_INVERT_HWHEEL                        0x00004000
 #define HID_QUIRK_POWERBOOK_ISO_KEYBOARD        0x00008000
 #define HID_QUIRK_BAD_RELATIVE_KEYS            0x00010000
+#define HID_QUIRK_SKIP_OUTPUT_REPORTS          0x00020000
+#define HID_QUIRK_IGNORE_MOUSE                 0x00040000
+#define HID_QUIRK_SONY_PS3_CONTROLLER          0x00080000
 
 /*
  * This is the global environment of the parser. This information is
@@ -430,8 +433,8 @@ struct hid_device {                                                 /* device report descriptor */
 
        /* device-specific function pointers */
        int (*hidinput_input_event) (struct input_dev *, unsigned int, unsigned int, int);
-       int (*hidinput_open) (struct input_dev *);
-       void (*hidinput_close) (struct input_dev *);
+       int (*hid_open) (struct hid_device *);
+       void (*hid_close) (struct hid_device *);
 
        /* hiddev event handler */
        void (*hiddev_hid_event) (struct hid_device *, struct hid_field *field,
@@ -471,16 +474,6 @@ struct hid_descriptor {
        struct hid_class_descriptor desc[1];
 } __attribute__ ((packed));
 
-#ifdef DEBUG
-#include "hid-debug.h"
-#else
-#define hid_dump_input(a,b)    do { } while (0)
-#define hid_dump_device(c)     do { } while (0)
-#define hid_dump_field(a,b)    do { } while (0)
-#define resolv_usage(a)                do { } while (0)
-#define resolv_event(a,b)      do { } while (0)
-#endif
-
 /* Applications from HID Usage Tables 4/8/99 Version 1.1 */
 /* We ignore a few input applications that are not widely used */
 #define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || (a == 0x000c0001))
@@ -503,6 +496,7 @@ struct hid_device *hid_parse_report(__u8 *start, unsigned size);
 int hid_ff_init(struct hid_device *hid);
 
 int hid_lgff_init(struct hid_device *hid);
+int hid_plff_init(struct hid_device *hid);
 int hid_tmff_init(struct hid_device *hid);
 int hid_zpff_init(struct hid_device *hid);
 #ifdef CONFIG_HID_PID
index e26a039..04e0fa9 100644 (file)
@@ -18,6 +18,9 @@
 #include <linux/device.h>
 #include <linux/pci.h>
 #include <linux/completion.h>
+#ifdef CONFIG_BLK_DEV_IDEACPI
+#include <acpi/acpi.h>
+#endif
 #include <asm/byteorder.h>
 #include <asm/system.h>
 #include <asm/io.h>
@@ -541,6 +544,11 @@ typedef enum {
 struct ide_driver_s;
 struct ide_settings_s;
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+struct ide_acpi_drive_link;
+struct ide_acpi_hwif_link;
+#endif
+
 typedef struct ide_drive_s {
        char            name[4];        /* drive name, such as "hda" */
         char            driver_req[10];        /* requests specific driver */
@@ -637,6 +645,9 @@ typedef struct ide_drive_s {
 
        int             lun;            /* logical unit */
        int             crc_count;      /* crc counter to reduce drive speed */
+#ifdef CONFIG_BLK_DEV_IDEACPI
+       struct ide_acpi_drive_link *acpidata;
+#endif
        struct list_head list;
        struct device   gendev;
        struct completion gendev_rel_comp;      /* to deal with device release() */
@@ -804,6 +815,10 @@ typedef struct hwif_s {
        void            *hwif_data;     /* extra hwif data */
 
        unsigned dma;
+
+#ifdef CONFIG_BLK_DEV_IDEACPI
+       struct ide_acpi_hwif_link *acpidata;
+#endif
 } ____cacheline_internodealigned_in_smp ide_hwif_t;
 
 /*
@@ -1192,8 +1207,8 @@ void ide_init_disk(struct gendisk *, ide_drive_t *);
 extern int ideprobe_init(void);
 
 extern void ide_scan_pcibus(int scan_direction) __init;
-extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner);
-#define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE)
+extern int __ide_pci_register_driver(struct pci_driver *driver, struct module *owner, const char *mod_name);
+#define ide_pci_register_driver(d) __ide_pci_register_driver(d, THIS_MODULE, KBUILD_MODNAME)
 void ide_pci_setup_ports(struct pci_dev *, struct ide_pci_device_s *, int, ata_index_t *);
 extern void ide_setup_pci_noise (struct pci_dev *dev, struct ide_pci_device_s *d);
 
@@ -1298,6 +1313,18 @@ static inline void ide_dma_verbose(ide_drive_t *drive) { ; }
 static inline void ide_release_dma(ide_hwif_t *drive) {;}
 #endif
 
+#ifdef CONFIG_BLK_DEV_IDEACPI
+extern int ide_acpi_exec_tfs(ide_drive_t *drive);
+extern void ide_acpi_get_timing(ide_hwif_t *hwif);
+extern void ide_acpi_push_timing(ide_hwif_t *hwif);
+extern void ide_acpi_init(ide_hwif_t *hwif);
+#else
+static inline int ide_acpi_exec_tfs(ide_drive_t *drive) { return 0; }
+static inline void ide_acpi_get_timing(ide_hwif_t *hwif) { ; }
+static inline void ide_acpi_push_timing(ide_hwif_t *hwif) { ; }
+static inline void ide_acpi_init(ide_hwif_t *hwif) { ; }
+#endif
+
 extern int ide_hwif_request_regions(ide_hwif_t *hwif);
 extern void ide_hwif_release_regions(ide_hwif_t* hwif);
 extern void ide_unregister (unsigned int index);
index 52fc405..5504b67 100644 (file)
@@ -68,6 +68,7 @@ typedef       void fastcall (*irq_flow_handler_t)(unsigned int irq,
 #define IRQ_MOVE_PENDING       0x40000000      /* need to re-target IRQ destination */
 
 struct proc_dir_entry;
+struct msi_desc;
 
 /**
  * struct irq_chip - hardware interrupt chip descriptor
@@ -148,6 +149,7 @@ struct irq_chip {
 struct irq_desc {
        irq_flow_handler_t      handle_irq;
        struct irq_chip         *chip;
+       struct msi_desc         *msi_desc;
        void                    *handler_data;
        void                    *chip_data;
        struct irqaction        *action;        /* IRQ action list */
@@ -373,10 +375,12 @@ extern int set_irq_chip(unsigned int irq, struct irq_chip *chip);
 extern int set_irq_data(unsigned int irq, void *data);
 extern int set_irq_chip_data(unsigned int irq, void *data);
 extern int set_irq_type(unsigned int irq, unsigned int type);
+extern int set_irq_msi(unsigned int irq, struct msi_desc *entry);
 
 #define get_irq_chip(irq)      (irq_desc[irq].chip)
 #define get_irq_chip_data(irq) (irq_desc[irq].chip_data)
 #define get_irq_data(irq)      (irq_desc[irq].handler_data)
+#define get_irq_msi(irq)       (irq_desc[irq].msi_desc)
 
 #endif /* CONFIG_GENERIC_HARDIRQS */
 
index 76538fc..b850e03 100644 (file)
@@ -74,9 +74,13 @@ extern void kobject_init(struct kobject *);
 extern void kobject_cleanup(struct kobject *);
 
 extern int __must_check kobject_add(struct kobject *);
+extern int __must_check kobject_shadow_add(struct kobject *, struct dentry *);
 extern void kobject_del(struct kobject *);
 
 extern int __must_check kobject_rename(struct kobject *, const char *new_name);
+extern int __must_check kobject_shadow_rename(struct kobject *kobj,
+                                               struct dentry *new_parent,
+                                               const char *new_name);
 extern int __must_check kobject_move(struct kobject *, struct kobject *);
 
 extern int __must_check kobject_register(struct kobject *);
index d0e6a54..e45712a 100644 (file)
@@ -71,6 +71,7 @@ struct mmc_card {
 #define MMC_STATE_SDCARD       (1<<3)          /* is an SD card */
 #define MMC_STATE_READONLY     (1<<4)          /* card is read-only */
 #define MMC_STATE_HIGHSPEED    (1<<5)          /* card is in high speed mode */
+#define MMC_STATE_BLOCKADDR    (1<<6)          /* card uses block-addressing */
        u32                     raw_cid[4];     /* raw card CID */
        u32                     raw_csd[4];     /* raw card CSD */
        u32                     raw_scr[2];     /* raw card SCR */
@@ -87,6 +88,7 @@ struct mmc_card {
 #define mmc_card_sd(c)         ((c)->state & MMC_STATE_SDCARD)
 #define mmc_card_readonly(c)   ((c)->state & MMC_STATE_READONLY)
 #define mmc_card_highspeed(c)  ((c)->state & MMC_STATE_HIGHSPEED)
+#define mmc_card_blockaddr(c)  ((c)->state & MMC_STATE_BLOCKADDR)
 
 #define mmc_card_set_present(c)        ((c)->state |= MMC_STATE_PRESENT)
 #define mmc_card_set_dead(c)   ((c)->state |= MMC_STATE_DEAD)
@@ -94,6 +96,7 @@ struct mmc_card {
 #define mmc_card_set_sd(c)     ((c)->state |= MMC_STATE_SDCARD)
 #define mmc_card_set_readonly(c) ((c)->state |= MMC_STATE_READONLY)
 #define mmc_card_set_highspeed(c) ((c)->state |= MMC_STATE_HIGHSPEED)
+#define mmc_card_set_blockaddr(c) ((c)->state |= MMC_STATE_BLOCKADDR)
 
 #define mmc_card_name(c)       ((c)->cid.prod_name)
 #define mmc_card_id(c)         ((c)->dev.bus_id)
index c15ae19..913e575 100644 (file)
@@ -92,8 +92,10 @@ struct mmc_host {
        unsigned int            max_seg_size;   /* see blk_queue_max_segment_size */
        unsigned short          max_hw_segs;    /* see blk_queue_max_hw_segments */
        unsigned short          max_phys_segs;  /* see blk_queue_max_phys_segments */
-       unsigned short          max_sectors;    /* see blk_queue_max_sectors */
        unsigned short          unused;
+       unsigned int            max_req_size;   /* maximum number of bytes in one req */
+       unsigned int            max_blk_size;   /* maximum size of one mmc block */
+       unsigned int            max_blk_count;  /* maximum number of blocks in one req */
 
        /* private data */
        struct mmc_ios          ios;            /* current io bus settings */
@@ -106,8 +108,9 @@ struct mmc_host {
        struct list_head        cards;          /* devices attached to this host */
 
        wait_queue_head_t       wq;
-       spinlock_t              lock;           /* card_busy lock */
-       struct mmc_card         *card_busy;     /* the MMC card claiming host */
+       spinlock_t              lock;           /* claimed lock */
+       unsigned int            claimed:1;      /* host exclusively claimed */
+
        struct mmc_card         *card_selected; /* the selected MMC card */
 
        struct delayed_work     detect;
@@ -126,6 +129,7 @@ static inline void *mmc_priv(struct mmc_host *host)
 }
 
 #define mmc_dev(x)     ((x)->parent)
+#define mmc_classdev(x)        (&(x)->class_dev)
 #define mmc_hostname(x)        ((x)->class_dev.bus_id)
 
 extern int mmc_suspend_host(struct mmc_host *, pm_message_t);
index bcf2490..cdc54be 100644 (file)
@@ -43,6 +43,7 @@ struct mmc_command {
 #define MMC_RSP_R2     (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
 #define MMC_RSP_R3     (MMC_RSP_PRESENT)
 #define MMC_RSP_R6     (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R7     (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
 
 #define mmc_resp_type(cmd)     ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
 
index 2dce60c..c90b676 100644 (file)
 #define MMC_GEN_CMD              56   /* adtc [0] RD/WR          R1  */
 
 /* SD commands                           type  argument     response */
-  /* class 8 */
+  /* class 0 */
 /* This is basically the same command as for MMC with some quirks. */
 #define SD_SEND_RELATIVE_ADDR     3   /* bcr                     R6  */
+#define SD_SEND_IF_COND           8   /* bcr  [11:0] See below   R7  */
+
+  /* class 10 */
 #define SD_SWITCH                 6   /* adtc [31:0] See below   R1  */
 
   /* Application commands */
  *      [3:0] Function group 1
  */
 
+/*
+ * SD_SEND_IF_COND argument format:
+ *
+ *     [31:12] Reserved (0)
+ *     [11:8] Host Voltage Supply Flags
+ *     [7:0] Check Pattern (0xAA)
+ */
+
 /*
   MMC status in R1
   Type
index 10f771a..419d3ef 100644 (file)
@@ -58,6 +58,7 @@ struct module_kobject
 {
        struct kobject kobj;
        struct module *mod;
+       struct kobject *drivers_dir;
 };
 
 /* These are either module local, or the kernel's dummy ones. */
@@ -263,7 +264,7 @@ struct module
        struct module_attribute *modinfo_attrs;
        const char *version;
        const char *srcversion;
-       struct kobject *drivers_dir;
+       struct kobject *holders_dir;
 
        /* Exported symbols */
        const struct kernel_symbol *syms;
index c7ef943..74c8a2e 100644 (file)
@@ -7,11 +7,10 @@ struct msi_msg {
        u32     data;           /* 16 bits of msi message data */
 };
 
-/* Heper functions */
+/* Helper functions */
 extern void mask_msi_irq(unsigned int irq);
 extern void unmask_msi_irq(unsigned int irq);
 extern void read_msi_msg(unsigned int irq, struct msi_msg *msg);
-
 extern void write_msi_msg(unsigned int irq, struct msi_msg *msg);
 
 struct msi_desc {
@@ -42,7 +41,7 @@ struct msi_desc {
 /*
  * The arch hook for setup up msi irqs
  */
-int arch_setup_msi_irq(unsigned int irq, struct pci_dev *dev);
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc);
 void arch_teardown_msi_irq(unsigned int irq);
 
 
index fea0d9d..2e37f50 100644 (file)
@@ -529,10 +529,11 @@ struct net_device
        struct net_bridge_port  *br_port;
 
        /* class/net/name entry */
-       struct class_device     class_dev;
+       struct device           dev;
        /* space for optional statistics and wireless sysfs groups */
        struct attribute_group  *sysfs_groups[3];
 };
+#define to_net_dev(d) container_of(d, struct net_device, dev)
 
 #define        NETDEV_ALIGN            32
 #define        NETDEV_ALIGN_CONST      (NETDEV_ALIGN - 1)
@@ -548,7 +549,7 @@ static inline void *netdev_priv(struct net_device *dev)
 /* Set the sysfs physical device reference for the network logical device
  * if set prior to registration will cause a symlink during initialization.
  */
-#define SET_NETDEV_DEV(net, pdev)      ((net)->class_dev.dev = (pdev))
+#define SET_NETDEV_DEV(net, pdev)      ((net)->dev.parent = (pdev))
 
 struct packet_type {
        __be16                  type;   /* This is really htons(ether_type). */
index f3c617e..805412c 100644 (file)
@@ -174,6 +174,9 @@ struct pci_dev {
        struct bin_attribute *rom_attr; /* attribute descriptor for sysfs ROM entry */
        int rom_attr_enabled;           /* has display of the rom attribute been enabled? */
        struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
+#ifdef CONFIG_PCI_MSI
+       unsigned int first_msi_irq;
+#endif
 };
 
 #define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)
@@ -181,6 +184,11 @@ struct pci_dev {
 #define        to_pci_dev(n) container_of(n, struct pci_dev, dev)
 #define for_each_pci_dev(d) while ((d = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, d)) != NULL)
 
+static inline int pci_channel_offline(struct pci_dev *pdev)
+{
+       return (pdev->error_state != pci_channel_io_normal);
+}
+
 static inline struct pci_cap_saved_state *pci_find_saved_cap(
        struct pci_dev *pci_dev,char cap)
 {
@@ -463,8 +471,7 @@ extern void pci_sort_breadthfirst(void);
 
 /* Generic PCI functions exported to card drivers */
 
-struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from);
-struct pci_dev *pci_find_device_reverse (unsigned int vendor, unsigned int device, const struct pci_dev *from);
+struct pci_dev __deprecated *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from);
 struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn);
 int pci_find_capability (struct pci_dev *dev, int cap);
 int pci_find_next_capability (struct pci_dev *dev, u8 pos, int cap);
@@ -533,6 +540,7 @@ void pci_update_resource(struct pci_dev *dev, struct resource *res, int resno);
 int __must_check pci_assign_resource(struct pci_dev *dev, int i);
 int __must_check pci_assign_resource_fixed(struct pci_dev *dev, int i);
 void pci_restore_bars(struct pci_dev *dev);
+int pci_select_bars(struct pci_dev *dev, unsigned long flags);
 
 /* ROM control related routines */
 void __iomem __must_check *pci_map_rom(struct pci_dev *pdev, size_t *size);
@@ -561,6 +569,8 @@ int __must_check pci_request_regions(struct pci_dev *, const char *);
 void pci_release_regions(struct pci_dev *);
 int __must_check pci_request_region(struct pci_dev *, int, const char *);
 void pci_release_region(struct pci_dev *, int);
+int pci_request_selected_regions(struct pci_dev *, int, const char *);
+void pci_release_selected_regions(struct pci_dev *, int);
 
 /* drivers/pci/bus.c */
 int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
@@ -573,10 +583,11 @@ int __must_check pci_bus_alloc_resource(struct pci_bus *bus,
 void pci_enable_bridges(struct pci_bus *bus);
 
 /* Proper probing supporting hot-pluggable devices */
-int __must_check __pci_register_driver(struct pci_driver *, struct module *);
+int __must_check __pci_register_driver(struct pci_driver *, struct module *,
+                                      const char *mod_name);
 static inline int __must_check pci_register_driver(struct pci_driver *driver)
 {
-       return __pci_register_driver(driver, THIS_MODULE);
+       return __pci_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
 }
 
 void pci_unregister_driver(struct pci_driver *);
@@ -611,10 +622,6 @@ enum pci_dma_burst_strategy {
                                   strategy_parameter byte boundaries */
 };
 
-#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
-extern struct pci_dev *isa_bridge;
-#endif
-
 struct msix_entry {
        u16     vector; /* kernel uses to write allocated vector */
        u16     entry;  /* driver uses to specify entry, OS writes */
@@ -622,7 +629,6 @@ struct msix_entry {
 
 
 #ifndef CONFIG_PCI_MSI
-static inline void pci_scan_msi_device(struct pci_dev *dev) {}
 static inline int pci_enable_msi(struct pci_dev *dev) {return -1;}
 static inline void pci_disable_msi(struct pci_dev *dev) {}
 static inline int pci_enable_msix(struct pci_dev* dev,
@@ -630,7 +636,6 @@ static inline int pci_enable_msix(struct pci_dev* dev,
 static inline void pci_disable_msix(struct pci_dev *dev) {}
 static inline void msi_remove_pci_irq_vectors(struct pci_dev *dev) {}
 #else
-extern void pci_scan_msi_device(struct pci_dev *dev);
 extern int pci_enable_msi(struct pci_dev *dev);
 extern void pci_disable_msi(struct pci_dev *dev);
 extern int pci_enable_msix(struct pci_dev* dev,
@@ -722,8 +727,6 @@ static inline int pci_set_power_state(struct pci_dev *dev, pci_power_t state) {
 static inline pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state) { return PCI_D0; }
 static inline int pci_enable_wake(struct pci_dev *dev, pci_power_t state, int enable) { return 0; }
 
-#define        isa_bridge      ((struct pci_dev *)NULL)
-
 #define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
 
 static inline void pci_block_user_cfg_access(struct pci_dev *dev) { }
index 3d1d210..defdeed 100644 (file)
 #define PCI_DEVICE_ID_TI_TVP4020       0x3d07
 #define PCI_DEVICE_ID_TI_4450          0x8011
 #define PCI_DEVICE_ID_TI_XX21_XX11     0x8031
+#define PCI_DEVICE_ID_TI_XX21_XX11_FM  0x8033
 #define PCI_DEVICE_ID_TI_XX21_XX11_SD  0x8034
 #define PCI_DEVICE_ID_TI_X515          0x8036
 #define PCI_DEVICE_ID_TI_XX12          0x8039
+#define PCI_DEVICE_ID_TI_XX12_FM       0x803b
 #define PCI_DEVICE_ID_TI_1130          0xac12
 #define PCI_DEVICE_ID_TI_1031          0xac13
 #define PCI_DEVICE_ID_TI_1131          0xac15
 #define PCI_DEVICE_ID_TI_1510          0xac56
 #define PCI_DEVICE_ID_TI_X620          0xac8d
 #define PCI_DEVICE_ID_TI_X420          0xac8e
+#define PCI_DEVICE_ID_TI_XX20_FM       0xac8f
 
 #define PCI_VENDOR_ID_SONY             0x104d
 
 
 #define PCI_VENDOR_ID_TOSHIBA_2                0x102f
 #define PCI_DEVICE_ID_TOSHIBA_TC35815CF        0x0030
+#define PCI_DEVICE_ID_TOSHIBA_TC86C001_IDE     0x0105
 #define PCI_DEVICE_ID_TOSHIBA_TC86C001_MISC    0x0108
 #define PCI_DEVICE_ID_TOSHIBA_SPIDER_NET 0x01b3
 
 #define PCI_DEVICE_ID_TOPIC_TP560      0x0000
 
 #define PCI_VENDOR_ID_ENE              0x1524
+#define PCI_DEVICE_ID_ENE_CB712_SD     0x0550
 #define PCI_DEVICE_ID_ENE_1211         0x1211
 #define PCI_DEVICE_ID_ENE_1225         0x1225
 #define PCI_DEVICE_ID_ENE_1410         0x1410
 #define PCI_VENDOR_ID_TDI               0x192E
 #define PCI_DEVICE_ID_TDI_EHCI          0x0101
 
+#define PCI_VENDOR_ID_PASEMI           0x1959
+
 #define PCI_VENDOR_ID_JMICRON          0x197B
 #define PCI_DEVICE_ID_JMICRON_JMB360   0x2360
 #define PCI_DEVICE_ID_JMICRON_JMB361   0x2361
index 0f478a8..ac2c70e 100644 (file)
@@ -86,6 +86,11 @@ static inline void serio_register_port(struct serio *serio)
 void serio_unregister_port(struct serio *serio);
 void serio_unregister_child_port(struct serio *serio);
 
+int __serio_register_driver(struct serio_driver *drv, struct module *owner, const char *mod_name);
+static inline int serio_register_driver(struct serio_driver *drv)
+{
+       return __serio_register_driver(drv, THIS_MODULE, KBUILD_MODNAME);
+}
 int serio_register_driver(struct serio_driver *drv);
 void serio_unregister_driver(struct serio_driver *drv);
 
index 176f6e3..8c2edd8 100644 (file)
@@ -170,7 +170,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
  * message's completion function when the transaction completes.
  */
 struct spi_master {
-       struct class_device     cdev;
+       struct device           dev;
 
        /* other than negative (== assign one dynamically), bus_num is fully
         * board-specific.  usually that simplifies to being SOC-specific.
@@ -216,17 +216,17 @@ struct spi_master {
 
 static inline void *spi_master_get_devdata(struct spi_master *master)
 {
-       return class_get_devdata(&master->cdev);
+       return dev_get_drvdata(&master->dev);
 }
 
 static inline void spi_master_set_devdata(struct spi_master *master, void *data)
 {
-       class_set_devdata(&master->cdev, data);
+       dev_set_drvdata(&master->dev, data);
 }
 
 static inline struct spi_master *spi_master_get(struct spi_master *master)
 {
-       if (!master || !class_device_get(&master->cdev))
+       if (!master || !get_device(&master->dev))
                return NULL;
        return master;
 }
@@ -234,7 +234,7 @@ static inline struct spi_master *spi_master_get(struct spi_master *master)
 static inline void spi_master_put(struct spi_master *master)
 {
        if (master)
-               class_device_put(&master->cdev);
+               put_device(&master->dev);
 }
 
 
index 2129d1b..192de3a 100644 (file)
 #define _SYSFS_H_
 
 #include <linux/compiler.h>
+#include <linux/list.h>
 #include <asm/atomic.h>
 
 struct kobject;
 struct module;
+struct nameidata;
 
 struct attribute {
        const char              * name;
@@ -88,13 +90,13 @@ struct sysfs_dirent {
 #ifdef CONFIG_SYSFS
 
 extern int __must_check
-sysfs_create_dir(struct kobject *);
+sysfs_create_dir(struct kobject *, struct dentry *);
 
 extern void
 sysfs_remove_dir(struct kobject *);
 
 extern int __must_check
-sysfs_rename_dir(struct kobject *, const char *new_name);
+sysfs_rename_dir(struct kobject *, struct dentry *, const char *new_name);
 
 extern int __must_check
 sysfs_move_dir(struct kobject *, struct kobject *);
@@ -126,11 +128,17 @@ int __must_check sysfs_create_group(struct kobject *,
 void sysfs_remove_group(struct kobject *, const struct attribute_group *);
 void sysfs_notify(struct kobject * k, char *dir, char *attr);
 
+
+extern int sysfs_make_shadowed_dir(struct kobject *kobj,
+       void * (*follow_link)(struct dentry *, struct nameidata *));
+extern struct dentry *sysfs_create_shadow_dir(struct kobject *kobj);
+extern void sysfs_remove_shadow_dir(struct dentry *dir);
+
 extern int __must_check sysfs_init(void);
 
 #else /* CONFIG_SYSFS */
 
-static inline int sysfs_create_dir(struct kobject * k)
+static inline int sysfs_create_dir(struct kobject * k, struct dentry *shadow)
 {
        return 0;
 }
@@ -140,7 +148,9 @@ static inline void sysfs_remove_dir(struct kobject * k)
        ;
 }
 
-static inline int sysfs_rename_dir(struct kobject * k, const char *new_name)
+static inline int sysfs_rename_dir(struct kobject * k,
+                                       struct dentry *new_parent,
+                                       const char *new_name)
 {
        return 0;
 }
@@ -204,6 +214,12 @@ static inline void sysfs_notify(struct kobject * k, char *dir, char *attr)
 {
 }
 
+static inline int sysfs_make_shadowed_dir(struct kobject *kobj,
+       void * (*follow_link)(struct dentry *, struct nameidata *))
+{
+       return 0;
+}
+
 static inline int __must_check sysfs_init(void)
 {
        return 0;
index dfb8052..3deb0a6 100644 (file)
@@ -17,7 +17,7 @@
 #include <linux/wait.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
-#include <linux/scatterlist.h>
+#include <linux/kthread.h>
 
 /* Host registers (relative to pci base address): */
 enum {
@@ -62,11 +62,10 @@ enum {
 
 
 #define TIFM_IRQ_ENABLE           0x80000000
-#define TIFM_IRQ_SOCKMASK         0x00000001
-#define TIFM_IRQ_CARDMASK         0x00000100
-#define TIFM_IRQ_FIFOMASK         0x00010000
+#define TIFM_IRQ_SOCKMASK(x)      (x)
+#define TIFM_IRQ_CARDMASK(x)      ((x) << 8)
+#define TIFM_IRQ_FIFOMASK(x)      ((x) << 16)
 #define TIFM_IRQ_SETALL           0xffffffff
-#define TIFM_IRQ_SETALLSOCK       0x0000000f
 
 #define TIFM_CTRL_LED             0x00000040
 #define TIFM_CTRL_FAST_CLK        0x00000100
@@ -89,10 +88,9 @@ struct tifm_dev {
        char __iomem            *addr;
        spinlock_t              lock;
        tifm_media_id           media_id;
-       char                    wq_name[KOBJ_NAME_LEN];
-       struct workqueue_struct *wq;
+       unsigned int            socket_id;
 
-       unsigned int            (*signal_irq)(struct tifm_dev *sock,
+       void                    (*signal_irq)(struct tifm_dev *sock,
                                              unsigned int sock_irq_status);
 
        struct tifm_driver      *drv;
@@ -103,24 +101,23 @@ struct tifm_driver {
        tifm_media_id        *id_table;
        int                  (*probe)(struct tifm_dev *dev);
        void                 (*remove)(struct tifm_dev *dev);
+       int                  (*suspend)(struct tifm_dev *dev,
+                                        pm_message_t state);
+       int                  (*resume)(struct tifm_dev *dev);
 
        struct device_driver driver;
 };
 
 struct tifm_adapter {
        char __iomem            *addr;
-       unsigned int            irq_status;
-       unsigned int            insert_mask;
-       unsigned int            remove_mask;
        spinlock_t              lock;
+       unsigned int            irq_status;
+       unsigned int            socket_change_set;
+       wait_queue_head_t       change_set_notify;
        unsigned int            id;
-       unsigned int            max_sockets;
-       char                    wq_name[KOBJ_NAME_LEN];
-       unsigned int            inhibit_new_cards;
-       struct workqueue_struct *wq;
-       struct work_struct      media_inserter;
-       struct work_struct      media_remover;
+       unsigned int            num_sockets;
        struct tifm_dev         **sockets;
+       struct task_struct      *media_switcher;
        struct class_device     cdev;
        struct device           *dev;
 
@@ -130,9 +127,9 @@ struct tifm_adapter {
 struct tifm_adapter *tifm_alloc_adapter(void);
 void tifm_free_device(struct device *dev);
 void tifm_free_adapter(struct tifm_adapter *fm);
-int tifm_add_adapter(struct tifm_adapter *fm);
+int tifm_add_adapter(struct tifm_adapter *fm, int (*mediathreadfn)(void *data));
 void tifm_remove_adapter(struct tifm_adapter *fm);
-struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm, unsigned int id);
+struct tifm_dev *tifm_alloc_device(struct tifm_adapter *fm);
 int tifm_register_driver(struct tifm_driver *drv);
 void tifm_unregister_driver(struct tifm_driver *drv);
 void tifm_eject(struct tifm_dev *sock);
index aab5b1b..b5c226a 100644 (file)
@@ -2,7 +2,7 @@
 #define __LINUX_USB_H
 
 #include <linux/mod_devicetable.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 
 #define USB_MAJOR                      180
 #define USB_DEVICE_MAJOR               189
@@ -107,7 +107,8 @@ enum usb_interface_condition {
  * @needs_remote_wakeup: flag set when the driver requires remote-wakeup
  *     capability during autosuspend.
  * @dev: driver model's view of this device
- * @class_dev: driver model's class view of this device.
+ * @usb_dev: if an interface is bound to the USB major, this will point
+ *     to the sysfs representation for that device.
  * @pm_usage_cnt: PM usage counter for this interface; autosuspend is not
  *     allowed unless the counter is 0.
  *
@@ -152,7 +153,7 @@ struct usb_interface {
        unsigned needs_remote_wakeup:1; /* driver requires remote wakeup */
 
        struct device dev;              /* interface specific device info */
-       struct class_device *class_dev;
+       struct device *usb_dev;         /* pointer to the usb class's device, if any */
        int pm_usage_cnt;               /* usage counter for autosuspend */
 };
 #define        to_usb_interface(d) container_of(d, struct usb_interface, dev)
@@ -372,7 +373,7 @@ struct usb_device {
        char *serial;                   /* iSerialNumber string, if present */
 
        struct list_head filelist;
-       struct class_device *class_dev;
+       struct device *usbfs_dev;
        struct dentry *usbfs_dentry;    /* usbfs dentry entry for the device */
 
        /*
@@ -475,6 +476,8 @@ extern void usb_driver_release_interface(struct usb_driver *driver,
                        struct usb_interface *iface);
 const struct usb_device_id *usb_match_id(struct usb_interface *interface,
                                         const struct usb_device_id *id);
+extern int usb_match_one_id(struct usb_interface *interface,
+                           const struct usb_device_id *id);
 
 extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
                int minor);
@@ -553,6 +556,18 @@ static inline int usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *e
                USB_ENDPOINT_XFER_BULK);
 }
 
+/**
+ * usb_endpoint_xfer_control - check if the endpoint has control transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type control, otherwise it returns false.
+ */
+static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
+{
+       return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+               USB_ENDPOINT_XFER_CONTROL);
+}
+
 /**
  * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
  * @epd: endpoint to be checked
@@ -723,11 +738,21 @@ static inline int usb_endpoint_is_isoc_out(const struct usb_endpoint_descriptor
 
 /* ----------------------------------------------------------------------- */
 
+/* Stuff for dynamic usb ids */
 struct usb_dynids {
        spinlock_t lock;
        struct list_head list;
 };
 
+struct usb_dynid {
+       struct list_head node;
+       struct usb_device_id id;
+};
+
+extern ssize_t usb_store_new_id(struct usb_dynids *dynids,
+                               struct device_driver *driver,
+                               const char *buf, size_t count);
+
 /**
  * struct usbdrv_wrap - wrapper for driver-model structure
  * @driver: The driver-model core driver structure.
@@ -868,10 +893,11 @@ struct usb_class_driver {
  * use these in module_init()/module_exit()
  * and don't forget MODULE_DEVICE_TABLE(usb, ...)
  */
-extern int usb_register_driver(struct usb_driver *, struct module *);
+extern int usb_register_driver(struct usb_driver *, struct module *,
+                              const char *);
 static inline int usb_register(struct usb_driver *driver)
 {
-       return usb_register_driver(driver, THIS_MODULE);
+       return usb_register_driver(driver, THIS_MODULE, KBUILD_MODNAME);
 }
 extern void usb_deregister(struct usb_driver *);
 
@@ -1085,7 +1111,6 @@ struct urb
        struct kref kref;               /* reference count of the URB */
        spinlock_t lock;                /* lock for the URB */
        void *hcpriv;                   /* private data for host controller */
-       int bandwidth;                  /* bandwidth for INT/ISO request */
        atomic_t use_count;             /* concurrent submissions counter */
        u8 reject;                      /* submissions will fail */
 
diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
new file mode 100644 (file)
index 0000000..43f160c
--- /dev/null
@@ -0,0 +1,5 @@
+unifdef-y += audio.h
+unifdef-y += cdc.h
+unifdef-y += ch9.h
+unifdef-y += midi.h
+
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
new file mode 100644 (file)
index 0000000..ae78337
--- /dev/null
@@ -0,0 +1,563 @@
+/*
+ * This file holds USB constants and structures that are needed for USB
+ * device APIs.  These are used by the USB device model, which is defined
+ * in chapter 9 of the USB 2.0 specification.  Linux has several APIs in C
+ * that need these:
+ *
+ * - the master/host side Linux-USB kernel driver API;
+ * - the "usbfs" user space API; and
+ * - the Linux "gadget" slave/device/peripheral side driver API.
+ *
+ * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
+ * act either as a USB master/host or as a USB slave/device.  That means
+ * the master and slave side APIs benefit from working well together.
+ *
+ * There's also "Wireless USB", using low power short range radios for
+ * peripheral interconnection but otherwise building on the USB framework.
+ */
+
+#ifndef __LINUX_USB_CH9_H
+#define __LINUX_USB_CH9_H
+
+#include <linux/types.h>       /* __u8 etc */
+
+/*-------------------------------------------------------------------------*/
+
+/* CONTROL REQUEST SUPPORT */
+
+/*
+ * USB directions
+ *
+ * This bit flag is used in endpoint descriptors' bEndpointAddress field.
+ * It's also one of three fields in control requests bRequestType.
+ */
+#define USB_DIR_OUT                    0               /* to device */
+#define USB_DIR_IN                     0x80            /* to host */
+
+/*
+ * USB types, the second of three bRequestType fields
+ */
+#define USB_TYPE_MASK                  (0x03 << 5)
+#define USB_TYPE_STANDARD              (0x00 << 5)
+#define USB_TYPE_CLASS                 (0x01 << 5)
+#define USB_TYPE_VENDOR                        (0x02 << 5)
+#define USB_TYPE_RESERVED              (0x03 << 5)
+
+/*
+ * USB recipients, the third of three bRequestType fields
+ */
+#define USB_RECIP_MASK                 0x1f
+#define USB_RECIP_DEVICE               0x00
+#define USB_RECIP_INTERFACE            0x01
+#define USB_RECIP_ENDPOINT             0x02
+#define USB_RECIP_OTHER                        0x03
+/* From Wireless USB 1.0 */
+#define USB_RECIP_PORT                         0x04
+#define USB_RECIP_RPIPE                0x05
+
+/*
+ * Standard requests, for the bRequest field of a SETUP packet.
+ *
+ * These are qualified by the bRequestType field, so that for example
+ * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved
+ * by a GET_STATUS request.
+ */
+#define USB_REQ_GET_STATUS             0x00
+#define USB_REQ_CLEAR_FEATURE          0x01
+#define USB_REQ_SET_FEATURE            0x03
+#define USB_REQ_SET_ADDRESS            0x05
+#define USB_REQ_GET_DESCRIPTOR         0x06
+#define USB_REQ_SET_DESCRIPTOR         0x07
+#define USB_REQ_GET_CONFIGURATION      0x08
+#define USB_REQ_SET_CONFIGURATION      0x09
+#define USB_REQ_GET_INTERFACE          0x0A
+#define USB_REQ_SET_INTERFACE          0x0B
+#define USB_REQ_SYNCH_FRAME            0x0C
+
+#define USB_REQ_SET_ENCRYPTION         0x0D    /* Wireless USB */
+#define USB_REQ_GET_ENCRYPTION         0x0E
+#define USB_REQ_RPIPE_ABORT            0x0E
+#define USB_REQ_SET_HANDSHAKE          0x0F
+#define USB_REQ_RPIPE_RESET            0x0F
+#define USB_REQ_GET_HANDSHAKE          0x10
+#define USB_REQ_SET_CONNECTION         0x11
+#define USB_REQ_SET_SECURITY_DATA      0x12
+#define USB_REQ_GET_SECURITY_DATA      0x13
+#define USB_REQ_SET_WUSB_DATA          0x14
+#define USB_REQ_LOOPBACK_DATA_WRITE    0x15
+#define USB_REQ_LOOPBACK_DATA_READ     0x16
+#define USB_REQ_SET_INTERFACE_DS       0x17
+
+/*
+ * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
+ * are read as a bit array returned by USB_REQ_GET_STATUS.  (So there
+ * are at most sixteen features of each type.)
+ */
+#define USB_DEVICE_SELF_POWERED                0       /* (read only) */
+#define USB_DEVICE_REMOTE_WAKEUP       1       /* dev may initiate wakeup */
+#define USB_DEVICE_TEST_MODE           2       /* (wired high speed only) */
+#define USB_DEVICE_BATTERY             2       /* (wireless) */
+#define USB_DEVICE_B_HNP_ENABLE                3       /* (otg) dev may initiate HNP */
+#define USB_DEVICE_WUSB_DEVICE         3       /* (wireless)*/
+#define USB_DEVICE_A_HNP_SUPPORT       4       /* (otg) RH port supports HNP */
+#define USB_DEVICE_A_ALT_HNP_SUPPORT   5       /* (otg) other RH port does */
+#define USB_DEVICE_DEBUG_MODE          6       /* (special devices only) */
+
+#define USB_ENDPOINT_HALT              0       /* IN/OUT will STALL */
+
+
+/**
+ * struct usb_ctrlrequest - SETUP data for a USB device control request
+ * @bRequestType: matches the USB bmRequestType field
+ * @bRequest: matches the USB bRequest field
+ * @wValue: matches the USB wValue field (le16 byte order)
+ * @wIndex: matches the USB wIndex field (le16 byte order)
+ * @wLength: matches the USB wLength field (le16 byte order)
+ *
+ * This structure is used to send control requests to a USB device.  It matches
+ * the different fields of the USB 2.0 Spec section 9.3, table 9-2.  See the
+ * USB spec for a fuller description of the different fields, and what they are
+ * used for.
+ *
+ * Note that the driver for any interface can issue control requests.
+ * For most devices, interfaces don't coordinate with each other, so
+ * such requests may be made at any time.
+ */
+struct usb_ctrlrequest {
+       __u8 bRequestType;
+       __u8 bRequest;
+       __le16 wValue;
+       __le16 wIndex;
+       __le16 wLength;
+} __attribute__ ((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or
+ * (rarely) accepted by SET_DESCRIPTOR.
+ *
+ * Note that all multi-byte values here are encoded in little endian
+ * byte order "on the wire".  But when exposed through Linux-USB APIs,
+ * they've been converted to cpu byte order.
+ */
+
+/*
+ * Descriptor types ... USB 2.0 spec table 9.5
+ */
+#define USB_DT_DEVICE                  0x01
+#define USB_DT_CONFIG                  0x02
+#define USB_DT_STRING                  0x03
+#define USB_DT_INTERFACE               0x04
+#define USB_DT_ENDPOINT                        0x05
+#define USB_DT_DEVICE_QUALIFIER                0x06
+#define USB_DT_OTHER_SPEED_CONFIG      0x07
+#define USB_DT_INTERFACE_POWER         0x08
+/* these are from a minor usb 2.0 revision (ECN) */
+#define USB_DT_OTG                     0x09
+#define USB_DT_DEBUG                   0x0a
+#define USB_DT_INTERFACE_ASSOCIATION   0x0b
+/* these are from the Wireless USB spec */
+#define USB_DT_SECURITY                        0x0c
+#define USB_DT_KEY                     0x0d
+#define USB_DT_ENCRYPTION_TYPE         0x0e
+#define USB_DT_BOS                     0x0f
+#define USB_DT_DEVICE_CAPABILITY       0x10
+#define USB_DT_WIRELESS_ENDPOINT_COMP  0x11
+#define USB_DT_WIRE_ADAPTER            0x21
+#define USB_DT_RPIPE                   0x22
+
+/* conventional codes for class-specific descriptors */
+#define USB_DT_CS_DEVICE               0x21
+#define USB_DT_CS_CONFIG               0x22
+#define USB_DT_CS_STRING               0x23
+#define USB_DT_CS_INTERFACE            0x24
+#define USB_DT_CS_ENDPOINT             0x25
+
+/* All standard descriptors have these 2 fields at the beginning */
+struct usb_descriptor_header {
+       __u8  bLength;
+       __u8  bDescriptorType;
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE: Device descriptor */
+struct usb_device_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 bcdUSB;
+       __u8  bDeviceClass;
+       __u8  bDeviceSubClass;
+       __u8  bDeviceProtocol;
+       __u8  bMaxPacketSize0;
+       __le16 idVendor;
+       __le16 idProduct;
+       __le16 bcdDevice;
+       __u8  iManufacturer;
+       __u8  iProduct;
+       __u8  iSerialNumber;
+       __u8  bNumConfigurations;
+} __attribute__ ((packed));
+
+#define USB_DT_DEVICE_SIZE             18
+
+
+/*
+ * Device and/or Interface Class codes
+ * as found in bDeviceClass or bInterfaceClass
+ * and defined by www.usb.org documents
+ */
+#define USB_CLASS_PER_INTERFACE                0       /* for DeviceClass */
+#define USB_CLASS_AUDIO                        1
+#define USB_CLASS_COMM                 2
+#define USB_CLASS_HID                  3
+#define USB_CLASS_PHYSICAL             5
+#define USB_CLASS_STILL_IMAGE          6
+#define USB_CLASS_PRINTER              7
+#define USB_CLASS_MASS_STORAGE         8
+#define USB_CLASS_HUB                  9
+#define USB_CLASS_CDC_DATA             0x0a
+#define USB_CLASS_CSCID                        0x0b    /* chip+ smart card */
+#define USB_CLASS_CONTENT_SEC          0x0d    /* content security */
+#define USB_CLASS_VIDEO                        0x0e
+#define USB_CLASS_WIRELESS_CONTROLLER  0xe0
+#define USB_CLASS_MISC                 0xef
+#define USB_CLASS_APP_SPEC             0xfe
+#define USB_CLASS_VENDOR_SPEC          0xff
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_CONFIG: Configuration descriptor information.
+ *
+ * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
+ * descriptor type is different.  Highspeed-capable devices can look
+ * different depending on what speed they're currently running.  Only
+ * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
+ * descriptors.
+ */
+struct usb_config_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 wTotalLength;
+       __u8  bNumInterfaces;
+       __u8  bConfigurationValue;
+       __u8  iConfiguration;
+       __u8  bmAttributes;
+       __u8  bMaxPower;
+} __attribute__ ((packed));
+
+#define USB_DT_CONFIG_SIZE             9
+
+/* from config descriptor bmAttributes */
+#define USB_CONFIG_ATT_ONE             (1 << 7)        /* must be set */
+#define USB_CONFIG_ATT_SELFPOWER       (1 << 6)        /* self powered */
+#define USB_CONFIG_ATT_WAKEUP          (1 << 5)        /* can wakeup */
+#define USB_CONFIG_ATT_BATTERY         (1 << 4)        /* battery powered */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_STRING: String descriptor */
+struct usb_string_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 wData[1];                /* UTF-16LE encoded */
+} __attribute__ ((packed));
+
+/* note that "string" zero is special, it holds language codes that
+ * the device supports, not Unicode characters.
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_INTERFACE: Interface descriptor */
+struct usb_interface_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bInterfaceNumber;
+       __u8  bAlternateSetting;
+       __u8  bNumEndpoints;
+       __u8  bInterfaceClass;
+       __u8  bInterfaceSubClass;
+       __u8  bInterfaceProtocol;
+       __u8  iInterface;
+} __attribute__ ((packed));
+
+#define USB_DT_INTERFACE_SIZE          9
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_ENDPOINT: Endpoint descriptor */
+struct usb_endpoint_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bEndpointAddress;
+       __u8  bmAttributes;
+       __le16 wMaxPacketSize;
+       __u8  bInterval;
+
+       /* NOTE:  these two are _only_ in audio endpoints. */
+       /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
+       __u8  bRefresh;
+       __u8  bSynchAddress;
+} __attribute__ ((packed));
+
+#define USB_DT_ENDPOINT_SIZE           7
+#define USB_DT_ENDPOINT_AUDIO_SIZE     9       /* Audio extension */
+
+
+/*
+ * Endpoints
+ */
+#define USB_ENDPOINT_NUMBER_MASK       0x0f    /* in bEndpointAddress */
+#define USB_ENDPOINT_DIR_MASK          0x80
+
+#define USB_ENDPOINT_XFERTYPE_MASK     0x03    /* in bmAttributes */
+#define USB_ENDPOINT_XFER_CONTROL      0
+#define USB_ENDPOINT_XFER_ISOC         1
+#define USB_ENDPOINT_XFER_BULK         2
+#define USB_ENDPOINT_XFER_INT          3
+#define USB_ENDPOINT_MAX_ADJUSTABLE    0x80
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
+struct usb_qualifier_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 bcdUSB;
+       __u8  bDeviceClass;
+       __u8  bDeviceSubClass;
+       __u8  bDeviceProtocol;
+       __u8  bMaxPacketSize0;
+       __u8  bNumConfigurations;
+       __u8  bRESERVED;
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_OTG (from OTG 1.0a supplement) */
+struct usb_otg_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bmAttributes;     /* support for HNP, SRP, etc */
+} __attribute__ ((packed));
+
+/* from usb_otg_descriptor.bmAttributes */
+#define USB_OTG_SRP            (1 << 0)
+#define USB_OTG_HNP            (1 << 1)        /* swap host/device roles */
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEBUG:  for special highspeed devices, replacing serial console */
+struct usb_debug_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       /* bulk endpoints with 8 byte maxpacket */
+       __u8  bDebugInEndpoint;
+       __u8  bDebugOutEndpoint;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */
+struct usb_interface_assoc_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bFirstInterface;
+       __u8  bInterfaceCount;
+       __u8  bFunctionClass;
+       __u8  bFunctionSubClass;
+       __u8  bFunctionProtocol;
+       __u8  iFunction;
+} __attribute__ ((packed));
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_SECURITY:  group of wireless security descriptors, including
+ * encryption types available for setting up a CC/association.
+ */
+struct usb_security_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 wTotalLength;
+       __u8  bNumEncryptionTypes;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_KEY:  used with {GET,SET}_SECURITY_DATA; only public keys
+ * may be retrieved.
+ */
+struct usb_key_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  tTKID[3];
+       __u8  bReserved;
+       __u8  bKeyData[0];
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_ENCRYPTION_TYPE:  bundled in DT_SECURITY groups */
+struct usb_encryption_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bEncryptionType;
+#define        USB_ENC_TYPE_UNSECURE           0
+#define        USB_ENC_TYPE_WIRED              1       /* non-wireless mode */
+#define        USB_ENC_TYPE_CCM_1              2       /* aes128/cbc session */
+#define        USB_ENC_TYPE_RSA_1              3       /* rsa3072/sha1 auth */
+       __u8  bEncryptionValue;         /* use in SET_ENCRYPTION */
+       __u8  bAuthKeyIndex;
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_BOS:  group of wireless capabilities */
+struct usb_bos_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __le16 wTotalLength;
+       __u8  bNumDeviceCaps;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE_CAPABILITY:  grouped with BOS */
+struct usb_dev_cap_header {
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDevCapabilityType;
+};
+
+#define        USB_CAP_TYPE_WIRELESS_USB       1
+
+struct usb_wireless_cap_descriptor {   /* Ultra Wide Band */
+       __u8  bLength;
+       __u8  bDescriptorType;
+       __u8  bDevCapabilityType;
+
+       __u8  bmAttributes;
+#define        USB_WIRELESS_P2P_DRD            (1 << 1)
+#define        USB_WIRELESS_BEACON_MASK        (3 << 2)
+#define        USB_WIRELESS_BEACON_SELF        (1 << 2)
+#define        USB_WIRELESS_BEACON_DIRECTED    (2 << 2)
+#define        USB_WIRELESS_BEACON_NONE        (3 << 2)
+       __le16 wPHYRates;       /* bit rates, Mbps */
+#define        USB_WIRELESS_PHY_53             (1 << 0)        /* always set */
+#define        USB_WIRELESS_PHY_80             (1 << 1)
+#define        USB_WIRELESS_PHY_107            (1 << 2)        /* always set */
+#define        USB_WIRELESS_PHY_160            (1 << 3)
+#define        USB_WIRELESS_PHY_200            (1 << 4)        /* always set */
+#define        USB_WIRELESS_PHY_320            (1 << 5)
+#define        USB_WIRELESS_PHY_400            (1 << 6)
+#define        USB_WIRELESS_PHY_480            (1 << 7)
+       __u8  bmTFITXPowerInfo; /* TFI power levels */
+       __u8  bmFFITXPowerInfo; /* FFI power levels */
+       __le16 bmBandGroup;
+       __u8  bReserved;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_WIRELESS_ENDPOINT_COMP:  companion descriptor associated with
+ * each endpoint descriptor for a wireless device
+ */
+struct usb_wireless_ep_comp_descriptor {
+       __u8  bLength;
+       __u8  bDescriptorType;
+
+       __u8  bMaxBurst;
+       __u8  bMaxSequence;
+       __le16 wMaxStreamDelay;
+       __le16 wOverTheAirPacketSize;
+       __u8  bOverTheAirInterval;
+       __u8  bmCompAttributes;
+#define USB_ENDPOINT_SWITCH_MASK       0x03    /* in bmCompAttributes */
+#define USB_ENDPOINT_SWITCH_NO         0
+#define USB_ENDPOINT_SWITCH_SWITCH     1
+#define USB_ENDPOINT_SWITCH_SCALE      2
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless
+ * host and a device for connection set up, mutual authentication, and
+ * exchanging short lived session keys.  The handshake depends on a CC.
+ */
+struct usb_handshake {
+       __u8 bMessageNumber;
+       __u8 bStatus;
+       __u8 tTKID[3];
+       __u8 bReserved;
+       __u8 CDID[16];
+       __u8 nonce[16];
+       __u8 MIC[8];
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC).
+ * A CC may also be set up using non-wireless secure channels (including
+ * wired USB!), and some devices may support CCs with multiple hosts.
+ */
+struct usb_connection_context {
+       __u8 CHID[16];          /* persistent host id */
+       __u8 CDID[16];          /* device id (unique w/in host context) */
+       __u8 CK[16];            /* connection key */
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB 2.0 defines three speeds, here's how Linux identifies them */
+
+enum usb_device_speed {
+       USB_SPEED_UNKNOWN = 0,                  /* enumerating */
+       USB_SPEED_LOW, USB_SPEED_FULL,          /* usb 1.1 */
+       USB_SPEED_HIGH,                         /* usb 2.0 */
+       USB_SPEED_VARIABLE,                     /* wireless (usb 2.5) */
+};
+
+enum usb_device_state {
+       /* NOTATTACHED isn't in the USB spec, and this state acts
+        * the same as ATTACHED ... but it's clearer this way.
+        */
+       USB_STATE_NOTATTACHED = 0,
+
+       /* chapter 9 and authentication (wireless) device states */
+       USB_STATE_ATTACHED,
+       USB_STATE_POWERED,                      /* wired */
+       USB_STATE_UNAUTHENTICATED,              /* auth */
+       USB_STATE_RECONNECTING,                 /* auth */
+       USB_STATE_DEFAULT,                      /* limited function */
+       USB_STATE_ADDRESS,
+       USB_STATE_CONFIGURED,                   /* most functions */
+
+       USB_STATE_SUSPENDED
+
+       /* NOTE:  there are actually four different SUSPENDED
+        * states, returning to POWERED, DEFAULT, ADDRESS, or
+        * CONFIGURED respectively when SOF tokens flow again.
+        */
+};
+
+#endif /* __LINUX_USB_CH9_H */
index 10f99e5..33dcd85 100644 (file)
@@ -179,6 +179,9 @@ static inline void usb_set_serial_data (struct usb_serial *serial, void *data)
  *     memory structure allocation at this point in time.
  * @shutdown: pointer to the driver's shutdown function.  This will be
  *     called when the device is removed from the system.
+ * @usb_driver: pointer to the struct usb_driver that controls this
+ *     device.  This is necessary to allow dynamic ids to be added to
+ *     the driver from sysfs.
  *
  * This structure is defines a USB Serial driver.  It provides all of
  * the information that the USB serial core code needs.  If the function
@@ -202,6 +205,8 @@ struct usb_serial_driver {
 
        struct list_head        driver_list;
        struct device_driver    driver;
+       struct usb_driver       *usb_driver;
+       struct usb_dynids       dynids;
 
        int (*probe) (struct usb_serial *serial, const struct usb_device_id *id);
        int (*attach) (struct usb_serial *serial);
diff --git a/include/linux/usb_ch9.h b/include/linux/usb_ch9.h
deleted file mode 100644 (file)
index c720d10..0000000
+++ /dev/null
@@ -1,562 +0,0 @@
-/*
- * This file holds USB constants and structures that are needed for USB
- * device APIs.  These are used by the USB device model, which is defined
- * in chapter 9 of the USB 2.0 specification.  Linux has several APIs in C
- * that need these:
- *
- * - the master/host side Linux-USB kernel driver API;
- * - the "usbfs" user space API; and
- * - the Linux "gadget" slave/device/peripheral side driver API.
- *
- * USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
- * act either as a USB master/host or as a USB slave/device.  That means
- * the master and slave side APIs benefit from working well together.
- *
- * There's also "Wireless USB", using low power short range radios for
- * peripheral interconnection but otherwise building on the USB framework.
- */
-
-#ifndef __LINUX_USB_CH9_H
-#define __LINUX_USB_CH9_H
-
-#include <linux/types.h>       /* __u8 etc */
-
-/*-------------------------------------------------------------------------*/
-
-/* CONTROL REQUEST SUPPORT */
-
-/*
- * USB directions
- *
- * This bit flag is used in endpoint descriptors' bEndpointAddress field.
- * It's also one of three fields in control requests bRequestType.
- */
-#define USB_DIR_OUT                    0               /* to device */
-#define USB_DIR_IN                     0x80            /* to host */
-
-/*
- * USB types, the second of three bRequestType fields
- */
-#define USB_TYPE_MASK                  (0x03 << 5)
-#define USB_TYPE_STANDARD              (0x00 << 5)
-#define USB_TYPE_CLASS                 (0x01 << 5)
-#define USB_TYPE_VENDOR                        (0x02 << 5)
-#define USB_TYPE_RESERVED              (0x03 << 5)
-
-/*
- * USB recipients, the third of three bRequestType fields
- */
-#define USB_RECIP_MASK                 0x1f
-#define USB_RECIP_DEVICE               0x00
-#define USB_RECIP_INTERFACE            0x01
-#define USB_RECIP_ENDPOINT             0x02
-#define USB_RECIP_OTHER                        0x03
-/* From Wireless USB 1.0 */
-#define USB_RECIP_PORT                         0x04
-#define USB_RECIP_RPIPE                0x05
-
-/*
- * Standard requests, for the bRequest field of a SETUP packet.
- *
- * These are qualified by the bRequestType field, so that for example
- * TYPE_CLASS or TYPE_VENDOR specific feature flags could be retrieved
- * by a GET_STATUS request.
- */
-#define USB_REQ_GET_STATUS             0x00
-#define USB_REQ_CLEAR_FEATURE          0x01
-#define USB_REQ_SET_FEATURE            0x03
-#define USB_REQ_SET_ADDRESS            0x05
-#define USB_REQ_GET_DESCRIPTOR         0x06
-#define USB_REQ_SET_DESCRIPTOR         0x07
-#define USB_REQ_GET_CONFIGURATION      0x08
-#define USB_REQ_SET_CONFIGURATION      0x09
-#define USB_REQ_GET_INTERFACE          0x0A
-#define USB_REQ_SET_INTERFACE          0x0B
-#define USB_REQ_SYNCH_FRAME            0x0C
-
-#define USB_REQ_SET_ENCRYPTION         0x0D    /* Wireless USB */
-#define USB_REQ_GET_ENCRYPTION         0x0E
-#define USB_REQ_RPIPE_ABORT            0x0E
-#define USB_REQ_SET_HANDSHAKE          0x0F
-#define USB_REQ_RPIPE_RESET            0x0F
-#define USB_REQ_GET_HANDSHAKE          0x10
-#define USB_REQ_SET_CONNECTION         0x11
-#define USB_REQ_SET_SECURITY_DATA      0x12
-#define USB_REQ_GET_SECURITY_DATA      0x13
-#define USB_REQ_SET_WUSB_DATA          0x14
-#define USB_REQ_LOOPBACK_DATA_WRITE    0x15
-#define USB_REQ_LOOPBACK_DATA_READ     0x16
-#define USB_REQ_SET_INTERFACE_DS       0x17
-
-/*
- * USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
- * are read as a bit array returned by USB_REQ_GET_STATUS.  (So there
- * are at most sixteen features of each type.)
- */
-#define USB_DEVICE_SELF_POWERED                0       /* (read only) */
-#define USB_DEVICE_REMOTE_WAKEUP       1       /* dev may initiate wakeup */
-#define USB_DEVICE_TEST_MODE           2       /* (wired high speed only) */
-#define USB_DEVICE_BATTERY             2       /* (wireless) */
-#define USB_DEVICE_B_HNP_ENABLE                3       /* (otg) dev may initiate HNP */
-#define USB_DEVICE_WUSB_DEVICE         3       /* (wireless)*/
-#define USB_DEVICE_A_HNP_SUPPORT       4       /* (otg) RH port supports HNP */
-#define USB_DEVICE_A_ALT_HNP_SUPPORT   5       /* (otg) other RH port does */
-#define USB_DEVICE_DEBUG_MODE          6       /* (special devices only) */
-
-#define USB_ENDPOINT_HALT              0       /* IN/OUT will STALL */
-
-
-/**
- * struct usb_ctrlrequest - SETUP data for a USB device control request
- * @bRequestType: matches the USB bmRequestType field
- * @bRequest: matches the USB bRequest field
- * @wValue: matches the USB wValue field (le16 byte order)
- * @wIndex: matches the USB wIndex field (le16 byte order)
- * @wLength: matches the USB wLength field (le16 byte order)
- *
- * This structure is used to send control requests to a USB device.  It matches
- * the different fields of the USB 2.0 Spec section 9.3, table 9-2.  See the
- * USB spec for a fuller description of the different fields, and what they are
- * used for.
- *
- * Note that the driver for any interface can issue control requests.
- * For most devices, interfaces don't coordinate with each other, so
- * such requests may be made at any time.
- */
-struct usb_ctrlrequest {
-       __u8 bRequestType;
-       __u8 bRequest;
-       __le16 wValue;
-       __le16 wIndex;
-       __le16 wLength;
-} __attribute__ ((packed));
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * STANDARD DESCRIPTORS ... as returned by GET_DESCRIPTOR, or
- * (rarely) accepted by SET_DESCRIPTOR.
- *
- * Note that all multi-byte values here are encoded in little endian
- * byte order "on the wire".  But when exposed through Linux-USB APIs,
- * they've been converted to cpu byte order.
- */
-
-/*
- * Descriptor types ... USB 2.0 spec table 9.5
- */
-#define USB_DT_DEVICE                  0x01
-#define USB_DT_CONFIG                  0x02
-#define USB_DT_STRING                  0x03
-#define USB_DT_INTERFACE               0x04
-#define USB_DT_ENDPOINT                        0x05
-#define USB_DT_DEVICE_QUALIFIER                0x06
-#define USB_DT_OTHER_SPEED_CONFIG      0x07
-#define USB_DT_INTERFACE_POWER         0x08
-/* these are from a minor usb 2.0 revision (ECN) */
-#define USB_DT_OTG                     0x09
-#define USB_DT_DEBUG                   0x0a
-#define USB_DT_INTERFACE_ASSOCIATION   0x0b
-/* these are from the Wireless USB spec */
-#define USB_DT_SECURITY                        0x0c
-#define USB_DT_KEY                     0x0d
-#define USB_DT_ENCRYPTION_TYPE         0x0e
-#define USB_DT_BOS                     0x0f
-#define USB_DT_DEVICE_CAPABILITY       0x10
-#define USB_DT_WIRELESS_ENDPOINT_COMP  0x11
-#define USB_DT_WIRE_ADAPTER            0x21
-#define USB_DT_RPIPE                   0x22
-
-/* conventional codes for class-specific descriptors */
-#define USB_DT_CS_DEVICE               0x21
-#define USB_DT_CS_CONFIG               0x22
-#define USB_DT_CS_STRING               0x23
-#define USB_DT_CS_INTERFACE            0x24
-#define USB_DT_CS_ENDPOINT             0x25
-
-/* All standard descriptors have these 2 fields at the beginning */
-struct usb_descriptor_header {
-       __u8  bLength;
-       __u8  bDescriptorType;
-} __attribute__ ((packed));
-
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_DEVICE: Device descriptor */
-struct usb_device_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __le16 bcdUSB;
-       __u8  bDeviceClass;
-       __u8  bDeviceSubClass;
-       __u8  bDeviceProtocol;
-       __u8  bMaxPacketSize0;
-       __le16 idVendor;
-       __le16 idProduct;
-       __le16 bcdDevice;
-       __u8  iManufacturer;
-       __u8  iProduct;
-       __u8  iSerialNumber;
-       __u8  bNumConfigurations;
-} __attribute__ ((packed));
-
-#define USB_DT_DEVICE_SIZE             18
-
-
-/*
- * Device and/or Interface Class codes
- * as found in bDeviceClass or bInterfaceClass
- * and defined by www.usb.org documents
- */
-#define USB_CLASS_PER_INTERFACE                0       /* for DeviceClass */
-#define USB_CLASS_AUDIO                        1
-#define USB_CLASS_COMM                 2
-#define USB_CLASS_HID                  3
-#define USB_CLASS_PHYSICAL             5
-#define USB_CLASS_STILL_IMAGE          6
-#define USB_CLASS_PRINTER              7
-#define USB_CLASS_MASS_STORAGE         8
-#define USB_CLASS_HUB                  9
-#define USB_CLASS_CDC_DATA             0x0a
-#define USB_CLASS_CSCID                        0x0b    /* chip+ smart card */
-#define USB_CLASS_CONTENT_SEC          0x0d    /* content security */
-#define USB_CLASS_VIDEO                        0x0e
-#define USB_CLASS_WIRELESS_CONTROLLER  0xe0
-#define USB_CLASS_APP_SPEC             0xfe
-#define USB_CLASS_VENDOR_SPEC          0xff
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_CONFIG: Configuration descriptor information.
- *
- * USB_DT_OTHER_SPEED_CONFIG is the same descriptor, except that the
- * descriptor type is different.  Highspeed-capable devices can look
- * different depending on what speed they're currently running.  Only
- * devices with a USB_DT_DEVICE_QUALIFIER have any OTHER_SPEED_CONFIG
- * descriptors.
- */
-struct usb_config_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __le16 wTotalLength;
-       __u8  bNumInterfaces;
-       __u8  bConfigurationValue;
-       __u8  iConfiguration;
-       __u8  bmAttributes;
-       __u8  bMaxPower;
-} __attribute__ ((packed));
-
-#define USB_DT_CONFIG_SIZE             9
-
-/* from config descriptor bmAttributes */
-#define USB_CONFIG_ATT_ONE             (1 << 7)        /* must be set */
-#define USB_CONFIG_ATT_SELFPOWER       (1 << 6)        /* self powered */
-#define USB_CONFIG_ATT_WAKEUP          (1 << 5)        /* can wakeup */
-#define USB_CONFIG_ATT_BATTERY         (1 << 4)        /* battery powered */
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_STRING: String descriptor */
-struct usb_string_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __le16 wData[1];                /* UTF-16LE encoded */
-} __attribute__ ((packed));
-
-/* note that "string" zero is special, it holds language codes that
- * the device supports, not Unicode characters.
- */
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_INTERFACE: Interface descriptor */
-struct usb_interface_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  bInterfaceNumber;
-       __u8  bAlternateSetting;
-       __u8  bNumEndpoints;
-       __u8  bInterfaceClass;
-       __u8  bInterfaceSubClass;
-       __u8  bInterfaceProtocol;
-       __u8  iInterface;
-} __attribute__ ((packed));
-
-#define USB_DT_INTERFACE_SIZE          9
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_ENDPOINT: Endpoint descriptor */
-struct usb_endpoint_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  bEndpointAddress;
-       __u8  bmAttributes;
-       __le16 wMaxPacketSize;
-       __u8  bInterval;
-
-       /* NOTE:  these two are _only_ in audio endpoints. */
-       /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
-       __u8  bRefresh;
-       __u8  bSynchAddress;
-} __attribute__ ((packed));
-
-#define USB_DT_ENDPOINT_SIZE           7
-#define USB_DT_ENDPOINT_AUDIO_SIZE     9       /* Audio extension */
-
-
-/*
- * Endpoints
- */
-#define USB_ENDPOINT_NUMBER_MASK       0x0f    /* in bEndpointAddress */
-#define USB_ENDPOINT_DIR_MASK          0x80
-
-#define USB_ENDPOINT_XFERTYPE_MASK     0x03    /* in bmAttributes */
-#define USB_ENDPOINT_XFER_CONTROL      0
-#define USB_ENDPOINT_XFER_ISOC         1
-#define USB_ENDPOINT_XFER_BULK         2
-#define USB_ENDPOINT_XFER_INT          3
-#define USB_ENDPOINT_MAX_ADJUSTABLE    0x80
-
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_DEVICE_QUALIFIER: Device Qualifier descriptor */
-struct usb_qualifier_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __le16 bcdUSB;
-       __u8  bDeviceClass;
-       __u8  bDeviceSubClass;
-       __u8  bDeviceProtocol;
-       __u8  bMaxPacketSize0;
-       __u8  bNumConfigurations;
-       __u8  bRESERVED;
-} __attribute__ ((packed));
-
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_OTG (from OTG 1.0a supplement) */
-struct usb_otg_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  bmAttributes;     /* support for HNP, SRP, etc */
-} __attribute__ ((packed));
-
-/* from usb_otg_descriptor.bmAttributes */
-#define USB_OTG_SRP            (1 << 0)
-#define USB_OTG_HNP            (1 << 1)        /* swap host/device roles */
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_DEBUG:  for special highspeed devices, replacing serial console */
-struct usb_debug_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       /* bulk endpoints with 8 byte maxpacket */
-       __u8  bDebugInEndpoint;
-       __u8  bDebugOutEndpoint;
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_INTERFACE_ASSOCIATION: groups interfaces */
-struct usb_interface_assoc_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  bFirstInterface;
-       __u8  bInterfaceCount;
-       __u8  bFunctionClass;
-       __u8  bFunctionSubClass;
-       __u8  bFunctionProtocol;
-       __u8  iFunction;
-} __attribute__ ((packed));
-
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_SECURITY:  group of wireless security descriptors, including
- * encryption types available for setting up a CC/association.
- */
-struct usb_security_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __le16 wTotalLength;
-       __u8  bNumEncryptionTypes;
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_KEY:  used with {GET,SET}_SECURITY_DATA; only public keys
- * may be retrieved.
- */
-struct usb_key_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  tTKID[3];
-       __u8  bReserved;
-       __u8  bKeyData[0];
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_ENCRYPTION_TYPE:  bundled in DT_SECURITY groups */
-struct usb_encryption_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  bEncryptionType;
-#define        USB_ENC_TYPE_UNSECURE           0
-#define        USB_ENC_TYPE_WIRED              1       /* non-wireless mode */
-#define        USB_ENC_TYPE_CCM_1              2       /* aes128/cbc session */
-#define        USB_ENC_TYPE_RSA_1              3       /* rsa3072/sha1 auth */
-       __u8  bEncryptionValue;         /* use in SET_ENCRYPTION */
-       __u8  bAuthKeyIndex;
-};
-
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_BOS:  group of wireless capabilities */
-struct usb_bos_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __le16 wTotalLength;
-       __u8  bNumDeviceCaps;
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_DEVICE_CAPABILITY:  grouped with BOS */
-struct usb_dev_cap_header {
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDevCapabilityType;
-};
-
-#define        USB_CAP_TYPE_WIRELESS_USB       1
-
-struct usb_wireless_cap_descriptor {   /* Ultra Wide Band */
-       __u8  bLength;
-       __u8  bDescriptorType;
-       __u8  bDevCapabilityType;
-
-       __u8  bmAttributes;
-#define        USB_WIRELESS_P2P_DRD            (1 << 1)
-#define        USB_WIRELESS_BEACON_MASK        (3 << 2)
-#define        USB_WIRELESS_BEACON_SELF        (1 << 2)
-#define        USB_WIRELESS_BEACON_DIRECTED    (2 << 2)
-#define        USB_WIRELESS_BEACON_NONE        (3 << 2)
-       __le16 wPHYRates;       /* bit rates, Mbps */
-#define        USB_WIRELESS_PHY_53             (1 << 0)        /* always set */
-#define        USB_WIRELESS_PHY_80             (1 << 1)
-#define        USB_WIRELESS_PHY_107            (1 << 2)        /* always set */
-#define        USB_WIRELESS_PHY_160            (1 << 3)
-#define        USB_WIRELESS_PHY_200            (1 << 4)        /* always set */
-#define        USB_WIRELESS_PHY_320            (1 << 5)
-#define        USB_WIRELESS_PHY_400            (1 << 6)
-#define        USB_WIRELESS_PHY_480            (1 << 7)
-       __u8  bmTFITXPowerInfo; /* TFI power levels */
-       __u8  bmFFITXPowerInfo; /* FFI power levels */
-       __le16 bmBandGroup;
-       __u8  bReserved;
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_DT_WIRELESS_ENDPOINT_COMP:  companion descriptor associated with
- * each endpoint descriptor for a wireless device
- */
-struct usb_wireless_ep_comp_descriptor {
-       __u8  bLength;
-       __u8  bDescriptorType;
-
-       __u8  bMaxBurst;
-       __u8  bMaxSequence;
-       __le16 wMaxStreamDelay;
-       __le16 wOverTheAirPacketSize;
-       __u8  bOverTheAirInterval;
-       __u8  bmCompAttributes;
-#define USB_ENDPOINT_SWITCH_MASK       0x03    /* in bmCompAttributes */
-#define USB_ENDPOINT_SWITCH_NO         0
-#define USB_ENDPOINT_SWITCH_SWITCH     1
-#define USB_ENDPOINT_SWITCH_SCALE      2
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless
- * host and a device for connection set up, mutual authentication, and
- * exchanging short lived session keys.  The handshake depends on a CC.
- */
-struct usb_handshake {
-       __u8 bMessageNumber;
-       __u8 bStatus;
-       __u8 tTKID[3];
-       __u8 bReserved;
-       __u8 CDID[16];
-       __u8 nonce[16];
-       __u8 MIC[8];
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC).
- * A CC may also be set up using non-wireless secure channels (including
- * wired USB!), and some devices may support CCs with multiple hosts.
- */
-struct usb_connection_context {
-       __u8 CHID[16];          /* persistent host id */
-       __u8 CDID[16];          /* device id (unique w/in host context) */
-       __u8 CK[16];            /* connection key */
-};
-
-/*-------------------------------------------------------------------------*/
-
-/* USB 2.0 defines three speeds, here's how Linux identifies them */
-
-enum usb_device_speed {
-       USB_SPEED_UNKNOWN = 0,                  /* enumerating */
-       USB_SPEED_LOW, USB_SPEED_FULL,          /* usb 1.1 */
-       USB_SPEED_HIGH,                         /* usb 2.0 */
-       USB_SPEED_VARIABLE,                     /* wireless (usb 2.5) */
-};
-
-enum usb_device_state {
-       /* NOTATTACHED isn't in the USB spec, and this state acts
-        * the same as ATTACHED ... but it's clearer this way.
-        */
-       USB_STATE_NOTATTACHED = 0,
-
-       /* chapter 9 and authentication (wireless) device states */
-       USB_STATE_ATTACHED,
-       USB_STATE_POWERED,                      /* wired */
-       USB_STATE_UNAUTHENTICATED,              /* auth */
-       USB_STATE_RECONNECTING,                 /* auth */
-       USB_STATE_DEFAULT,                      /* limited function */
-       USB_STATE_ADDRESS,
-       USB_STATE_CONFIGURED,                   /* most functions */
-
-       USB_STATE_SUSPENDED
-
-       /* NOTE:  there are actually four different SUSPENDED
-        * states, returning to POWERED, DEFAULT, ADDRESS, or
-        * CONFIGURED respectively when SOF tokens flow again.
-        */
-};
-
-#endif /* __LINUX_USB_CH9_H */
index b53d6ae..8086d5a 100644 (file)
@@ -2,7 +2,7 @@
 #include <asm/types.h>
 #include <asm/ioctl.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 
 /*
  * Filesystem based user-mode API to USB Gadget controller hardware
diff --git a/include/linux/video_output.h b/include/linux/video_output.h
new file mode 100644 (file)
index 0000000..e63e0c0
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *
+ *  Copyright (C) 2006 Luming Yu <luming.yu@intel.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or (at
+ *  your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef _LINUX_VIDEO_OUTPUT_H
+#define _LINUX_VIDEO_OUTPUT_H
+#include <linux/device.h>
+struct output_device;
+struct output_properties {
+       int (*set_state)(struct output_device *);
+       int (*get_status)(struct output_device *);
+};
+struct output_device {
+       int request_state;
+       struct output_properties *props;
+       struct class_device class_dev;
+};
+#define to_output_device(obj) container_of(obj, struct output_device, class_dev)
+struct output_device *video_output_register(const char *name,
+       struct device *dev,
+       void *devdata,
+       struct output_properties *op);
+void video_output_unregister(struct output_device *dev);
+#endif
index 623a0fc..6e84258 100644 (file)
@@ -284,7 +284,7 @@ struct pcmcia_socket {
 #endif
 
        /* socket device */
-       struct class_device             dev;
+       struct device                   dev;
        void                            *driver_data;   /* data internal to the socket driver */
 
 };
index 44537aa..d66b15e 100644 (file)
@@ -98,7 +98,7 @@ struct ib_user_mad_hdr {
  */
 struct ib_user_mad {
        struct ib_user_mad_hdr hdr;
-       __u   data[0];
+       __u64   data[0];
 };
 
 /**
index 0bfa332..765589f 100644 (file)
@@ -45,6 +45,7 @@
 #include <linux/device.h>
 #include <linux/mm.h>
 #include <linux/dma-mapping.h>
+#include <linux/kref.h>
 
 #include <asm/atomic.h>
 #include <asm/scatterlist.h>
@@ -419,8 +420,8 @@ struct ib_wc {
        enum ib_wc_opcode       opcode;
        u32                     vendor_err;
        u32                     byte_len;
+       struct ib_qp           *qp;
        __be32                  imm_data;
-       u32                     qp_num;
        u32                     src_qp;
        int                     wc_flags;
        u16                     pkey_index;
index d27b258..475e8a7 100644 (file)
@@ -39,6 +39,7 @@ void dynamic_irq_init(unsigned int irq)
        desc->chip = &no_irq_chip;
        desc->handle_irq = handle_bad_irq;
        desc->depth = 1;
+       desc->msi_desc = NULL;
        desc->handler_data = NULL;
        desc->chip_data = NULL;
        desc->action = NULL;
@@ -74,6 +75,9 @@ void dynamic_irq_cleanup(unsigned int irq)
                WARN_ON(1);
                return;
        }
+       desc->msi_desc = NULL;
+       desc->handler_data = NULL;
+       desc->chip_data = NULL;
        desc->handle_irq = handle_bad_irq;
        desc->chip = &no_irq_chip;
        spin_unlock_irqrestore(&desc->lock, flags);
@@ -161,6 +165,30 @@ int set_irq_data(unsigned int irq, void *data)
 }
 EXPORT_SYMBOL(set_irq_data);
 
+/**
+ *     set_irq_data - set irq type data for an irq
+ *     @irq:   Interrupt number
+ *     @data:  Pointer to interrupt specific data
+ *
+ *     Set the hardware irq controller data for an irq
+ */
+int set_irq_msi(unsigned int irq, struct msi_desc *entry)
+{
+       struct irq_desc *desc;
+       unsigned long flags;
+
+       if (irq >= NR_IRQS) {
+               printk(KERN_ERR
+                      "Trying to install msi data for IRQ%d\n", irq);
+               return -EINVAL;
+       }
+       desc = irq_desc + irq;
+       spin_lock_irqsave(&desc->lock, flags);
+       desc->msi_desc = entry;
+       spin_unlock_irqrestore(&desc->lock, flags);
+       return 0;
+}
+
 /**
  *     set_irq_chip_data - set irq chip data for an irq
  *     @irq:   Interrupt number
index d0f2260..8a94e05 100644 (file)
@@ -537,6 +537,8 @@ static int already_uses(struct module *a, struct module *b)
 static int use_module(struct module *a, struct module *b)
 {
        struct module_use *use;
+       int no_warn;
+
        if (b == NULL || already_uses(a, b)) return 1;
 
        if (!strong_try_module_get(b))
@@ -552,6 +554,7 @@ static int use_module(struct module *a, struct module *b)
 
        use->module_which_uses = a;
        list_add(&use->list, &b->modules_which_use_me);
+       no_warn = sysfs_create_link(b->holders_dir, &a->mkobj.kobj, a->name);
        return 1;
 }
 
@@ -569,6 +572,7 @@ static void module_unload_free(struct module *mod)
                                module_put(i);
                                list_del(&use->list);
                                kfree(use);
+                               sysfs_remove_link(i->holders_dir, mod->name);
                                /* There can be at most one match. */
                                break;
                        }
@@ -1106,9 +1110,7 @@ static void module_remove_modinfo_attrs(struct module *mod)
        kfree(mod->modinfo_attrs);
 }
 
-static int mod_sysfs_setup(struct module *mod,
-                          struct kernel_param *kparam,
-                          unsigned int num_params)
+static int mod_sysfs_init(struct module *mod)
 {
        int err;
 
@@ -1125,21 +1127,30 @@ static int mod_sysfs_setup(struct module *mod,
        kobj_set_kset_s(&mod->mkobj, module_subsys);
        mod->mkobj.mod = mod;
 
-       /* delay uevent until full sysfs population */
        kobject_init(&mod->mkobj.kobj);
+
+out:
+       return err;
+}
+
+static int mod_sysfs_setup(struct module *mod,
+                          struct kernel_param *kparam,
+                          unsigned int num_params)
+{
+       int err;
+
+       /* delay uevent until full sysfs population */
        err = kobject_add(&mod->mkobj.kobj);
        if (err)
                goto out;
 
-       mod->drivers_dir = kobject_add_dir(&mod->mkobj.kobj, "drivers");
-       if (!mod->drivers_dir) {
-               err = -ENOMEM;
+       mod->holders_dir = kobject_add_dir(&mod->mkobj.kobj, "holders");
+       if (!mod->holders_dir)
                goto out_unreg;
-       }
 
        err = module_param_sysfs_setup(mod, kparam, num_params);
        if (err)
-               goto out_unreg_drivers;
+               goto out_unreg_holders;
 
        err = module_add_modinfo_attrs(mod);
        if (err)
@@ -1150,8 +1161,8 @@ static int mod_sysfs_setup(struct module *mod,
 
 out_unreg_param:
        module_param_sysfs_remove(mod);
-out_unreg_drivers:
-       kobject_unregister(mod->drivers_dir);
+out_unreg_holders:
+       kobject_unregister(mod->holders_dir);
 out_unreg:
        kobject_del(&mod->mkobj.kobj);
        kobject_put(&mod->mkobj.kobj);
@@ -1163,7 +1174,10 @@ static void mod_kobject_remove(struct module *mod)
 {
        module_remove_modinfo_attrs(mod);
        module_param_sysfs_remove(mod);
-       kobject_unregister(mod->drivers_dir);
+       if (mod->mkobj.drivers_dir)
+               kobject_unregister(mod->mkobj.drivers_dir);
+       if (mod->holders_dir)
+               kobject_unregister(mod->holders_dir);
 
        kobject_unregister(&mod->mkobj.kobj);
 }
@@ -1768,6 +1782,10 @@ static struct module *load_module(void __user *umod,
        /* Now we've moved module, initialize linked lists, etc. */
        module_unload_init(mod);
 
+       /* Initialize kobject, so we can reference it. */
+       if (mod_sysfs_init(mod) != 0)
+               goto cleanup;
+
        /* Set up license info based on the info section */
        set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
 
@@ -2340,19 +2358,43 @@ static char *make_driver_name(struct device_driver *drv)
        return driver_name;
 }
 
+static void module_create_drivers_dir(struct module_kobject *mk)
+{
+       if (!mk || mk->drivers_dir)
+               return;
+
+       mk->drivers_dir = kobject_add_dir(&mk->kobj, "drivers");
+}
+
 void module_add_driver(struct module *mod, struct device_driver *drv)
 {
        char *driver_name;
        int no_warn;
+       struct module_kobject *mk = NULL;
+
+       if (!drv)
+               return;
+
+       if (mod)
+               mk = &mod->mkobj;
+       else if (drv->mod_name) {
+               struct kobject *mkobj;
+
+               /* Lookup built-in module entry in /sys/modules */
+               mkobj = kset_find_obj(&module_subsys.kset, drv->mod_name);
+               if (mkobj)
+                       mk = container_of(mkobj, struct module_kobject, kobj);
+       }
 
-       if (!mod || !drv)
+       if (!mk)
                return;
 
        /* Don't check return codes; these calls are idempotent */
-       no_warn = sysfs_create_link(&drv->kobj, &mod->mkobj.kobj, "module");
+       no_warn = sysfs_create_link(&drv->kobj, &mk->kobj, "module");
        driver_name = make_driver_name(drv);
        if (driver_name) {
-               no_warn = sysfs_create_link(mod->drivers_dir, &drv->kobj,
+               module_create_drivers_dir(mk);
+               no_warn = sysfs_create_link(mk->drivers_dir, &drv->kobj,
                                            driver_name);
                kfree(driver_name);
        }
@@ -2367,10 +2409,10 @@ void module_remove_driver(struct device_driver *drv)
                return;
 
        sysfs_remove_link(&drv->kobj, "module");
-       if (drv->owner && drv->owner->drivers_dir) {
+       if (drv->owner && drv->owner->mkobj.drivers_dir) {
                driver_name = make_driver_name(drv);
                if (driver_name) {
-                       sysfs_remove_link(drv->owner->drivers_dir,
+                       sysfs_remove_link(drv->owner->mkobj.drivers_dir,
                                          driver_name);
                        kfree(driver_name);
                }
index 718945d..553cf7d 100644 (file)
@@ -30,6 +30,8 @@
 #define DEBUGP(fmt, a...)
 #endif
 
+static struct kobj_type module_ktype;
+
 static inline char dash2underscore(char c)
 {
        if (c == '-')
@@ -561,14 +563,11 @@ static void __init kernel_param_sysfs_setup(const char *name,
        mk->mod = THIS_MODULE;
        kobj_set_kset_s(mk, module_subsys);
        kobject_set_name(&mk->kobj, name);
-       ret = kobject_register(&mk->kobj);
+       kobject_init(&mk->kobj);
+       ret = kobject_add(&mk->kobj);
        BUG_ON(ret < 0);
-
-       /* no need to keep the kobject if no parameter is exported */
-       if (!param_sysfs_setup(mk, kparam, num_params, name_skip)) {
-               kobject_unregister(&mk->kobj);
-               kfree(mk);
-       }
+       param_sysfs_setup(mk, kparam, num_params, name_skip);
+       kobject_uevent(&mk->kobj, KOBJ_ADD);
 }
 
 /*
@@ -674,6 +673,19 @@ static struct sysfs_ops module_sysfs_ops = {
        .store = module_attr_store,
 };
 
+static int uevent_filter(struct kset *kset, struct kobject *kobj)
+{
+       struct kobj_type *ktype = get_ktype(kobj);
+
+       if (ktype == &module_ktype)
+               return 1;
+       return 0;
+}
+
+static struct kset_uevent_ops module_uevent_ops = {
+       .filter = uevent_filter,
+};
+
 #else
 static struct sysfs_ops module_sysfs_ops = {
        .show = NULL,
@@ -685,7 +697,7 @@ static struct kobj_type module_ktype = {
        .sysfs_ops =    &module_sysfs_ops,
 };
 
-decl_subsys(module, &module_ktype, NULL);
+decl_subsys(module, &module_ktype, &module_uevent_ops);
 
 /*
  * param_sysfs_init - wrapper for built-in params support
index 7ce6dc1..c2917ff 100644 (file)
@@ -44,11 +44,11 @@ static int populate_dir(struct kobject * kobj)
        return error;
 }
 
-static int create_dir(struct kobject * kobj)
+static int create_dir(struct kobject * kobj, struct dentry *shadow_parent)
 {
        int error = 0;
        if (kobject_name(kobj)) {
-               error = sysfs_create_dir(kobj);
+               error = sysfs_create_dir(kobj, shadow_parent);
                if (!error) {
                        if ((error = populate_dir(kobj)))
                                sysfs_remove_dir(kobj);
@@ -126,6 +126,8 @@ EXPORT_SYMBOL_GPL(kobject_get_path);
  */
 void kobject_init(struct kobject * kobj)
 {
+       if (!kobj)
+               return;
        kref_init(&kobj->kref);
        INIT_LIST_HEAD(&kobj->entry);
        init_waitqueue_head(&kobj->poll);
@@ -156,9 +158,10 @@ static void unlink(struct kobject * kobj)
 /**
  *     kobject_add - add an object to the hierarchy.
  *     @kobj:  object.
+ *     @shadow_parent: sysfs directory to add to.
  */
 
-int kobject_add(struct kobject * kobj)
+int kobject_shadow_add(struct kobject * kobj, struct dentry *shadow_parent)
 {
        int error = 0;
        struct kobject * parent;
@@ -189,12 +192,11 @@ int kobject_add(struct kobject * kobj)
        }
        kobj->parent = parent;
 
-       error = create_dir(kobj);
+       error = create_dir(kobj, shadow_parent);
        if (error) {
                /* unlink does the kobject_put() for us */
                unlink(kobj);
-               if (parent)
-                       kobject_put(parent);
+               kobject_put(parent);
 
                /* be noisy on error issues */
                if (error == -EEXIST)
@@ -211,6 +213,15 @@ int kobject_add(struct kobject * kobj)
        return error;
 }
 
+/**
+ *     kobject_add - add an object to the hierarchy.
+ *     @kobj:  object.
+ */
+int kobject_add(struct kobject * kobj)
+{
+       return kobject_shadow_add(kobj, NULL);
+}
+
 
 /**
  *     kobject_register - initialize and add an object.
@@ -303,7 +314,29 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
        kobj = kobject_get(kobj);
        if (!kobj)
                return -EINVAL;
-       error = sysfs_rename_dir(kobj, new_name);
+       if (!kobj->parent)
+               return -EINVAL;
+       error = sysfs_rename_dir(kobj, kobj->parent->dentry, new_name);
+       kobject_put(kobj);
+
+       return error;
+}
+
+/**
+ *     kobject_rename - change the name of an object
+ *     @kobj:  object in question.
+ *     @new_name: object's new name
+ */
+
+int kobject_shadow_rename(struct kobject * kobj, struct dentry *new_parent,
+                         const char *new_name)
+{
+       int error = 0;
+
+       kobj = kobject_get(kobj);
+       if (!kobj)
+               return -EINVAL;
+       error = sysfs_rename_dir(kobj, new_parent, new_name);
        kobject_put(kobj);
 
        return error;
@@ -312,7 +345,7 @@ int kobject_rename(struct kobject * kobj, const char *new_name)
 /**
  *     kobject_move - move object to another parent
  *     @kobj:  object in question.
- *     @new_parent: object's new parent
+ *     @new_parent: object's new parent (can be NULL)
  */
 
 int kobject_move(struct kobject *kobj, struct kobject *new_parent)
@@ -328,8 +361,8 @@ int kobject_move(struct kobject *kobj, struct kobject *new_parent)
                return -EINVAL;
        new_parent = kobject_get(new_parent);
        if (!new_parent) {
-               error = -EINVAL;
-               goto out;
+               if (kobj->kset)
+                       new_parent = kobject_get(&kobj->kset->kobj);
        }
        /* old object path */
        devpath = kobject_get_path(kobj, GFP_KERNEL);
@@ -366,6 +399,8 @@ out:
 
 void kobject_del(struct kobject * kobj)
 {
+       if (!kobj)
+               return;
        sysfs_remove_dir(kobj);
        unlink(kobj);
 }
@@ -377,6 +412,8 @@ void kobject_del(struct kobject * kobj)
 
 void kobject_unregister(struct kobject * kobj)
 {
+       if (!kobj)
+               return;
        pr_debug("kobject %s: unregistering\n",kobject_name(kobj));
        kobject_uevent(kobj, KOBJ_REMOVE);
        kobject_del(kobj);
@@ -414,8 +451,7 @@ void kobject_cleanup(struct kobject * kobj)
                t->release(kobj);
        if (s)
                kset_put(s);
-       if (parent) 
-               kobject_put(parent);
+       kobject_put(parent);
 }
 
 static void kobject_release(struct kref *kref)
@@ -523,6 +559,8 @@ int kset_add(struct kset * k)
 
 int kset_register(struct kset * k)
 {
+       if (!k)
+               return -EINVAL;
        kset_init(k);
        return kset_add(k);
 }
@@ -535,6 +573,8 @@ int kset_register(struct kset * k)
 
 void kset_unregister(struct kset * k)
 {
+       if (!k)
+               return;
        kobject_unregister(&k->kobj);
 }
 
@@ -586,6 +626,9 @@ int subsystem_register(struct subsystem * s)
 {
        int error;
 
+       if (!s)
+               return -EINVAL;
+
        subsystem_init(s);
        pr_debug("subsystem %s: registering\n",s->kset.kobj.name);
 
@@ -598,6 +641,8 @@ int subsystem_register(struct subsystem * s)
 
 void subsystem_unregister(struct subsystem * s)
 {
+       if (!s)
+               return;
        pr_debug("subsystem %s: unregistering\n",s->kset.kobj.name);
        kset_unregister(&s->kset);
 }
@@ -612,6 +657,10 @@ void subsystem_unregister(struct subsystem * s)
 int subsys_create_file(struct subsystem * s, struct subsys_attribute * a)
 {
        int error = 0;
+
+       if (!s || !a)
+               return -EINVAL;
+
        if (subsys_get(s)) {
                error = sysfs_create_file(&s->kset.kobj,&a->attr);
                subsys_put(s);
index 1062578..50a4380 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Dynamic DMA mapping support.
  *
- * This implementation is for IA-64 and EM64T platforms that do not support
+ * This implementation is a fallback for platforms that do not support
  * I/O TLBs (aka DMA address translation hardware).
  * Copyright (C) 2000 Asit Mallick <Asit.K.Mallick@intel.com>
  * Copyright (C) 2000 Goutham Rao <goutham.rao@intel.com>
@@ -28,6 +28,7 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/scatterlist.h>
+#include <asm/swiotlb.h>
 
 #include <linux/init.h>
 #include <linux/bootmem.h>
 #define OFFSET(val,align) ((unsigned long)     \
                           ( (val) & ( (align) - 1)))
 
+#ifndef SG_ENT_VIRT_ADDRESS
 #define SG_ENT_VIRT_ADDRESS(sg)        (page_address((sg)->page) + (sg)->offset)
-#define SG_ENT_PHYS_ADDRESS(SG)        virt_to_phys(SG_ENT_VIRT_ADDRESS(SG))
+#define SG_ENT_PHYS_ADDRESS(sg)        virt_to_bus(SG_ENT_VIRT_ADDRESS(sg))
+#endif
 
 /*
  * Maximum allowable number of contiguous slabs to map,
@@ -101,13 +104,25 @@ static unsigned int io_tlb_index;
  * We need to save away the original address corresponding to a mapped entry
  * for the sync operations.
  */
-static unsigned char **io_tlb_orig_addr;
+#ifndef SWIOTLB_ARCH_HAS_IO_TLB_ADDR_T
+typedef char *io_tlb_addr_t;
+#define swiotlb_orig_addr_null(buffer) (!(buffer))
+#define ptr_to_io_tlb_addr(ptr) (ptr)
+#define page_to_io_tlb_addr(pg, off) (page_address(pg) + (off))
+#define sg_to_io_tlb_addr(sg) SG_ENT_VIRT_ADDRESS(sg)
+#endif
+static io_tlb_addr_t *io_tlb_orig_addr;
 
 /*
  * Protect the above data structures in the map and unmap calls
  */
 static DEFINE_SPINLOCK(io_tlb_lock);
 
+#ifdef SWIOTLB_EXTRA_VARIABLES
+SWIOTLB_EXTRA_VARIABLES;
+#endif
+
+#ifndef SWIOTLB_ARCH_HAS_SETUP_IO_TLB_NPAGES
 static int __init
 setup_io_tlb_npages(char *str)
 {
@@ -122,30 +137,50 @@ setup_io_tlb_npages(char *str)
                swiotlb_force = 1;
        return 1;
 }
+#endif
 __setup("swiotlb=", setup_io_tlb_npages);
 /* make io_tlb_overflow tunable too? */
 
+#ifndef swiotlb_adjust_size
+#define swiotlb_adjust_size(size) ((void)0)
+#endif
+
+#ifndef swiotlb_adjust_seg
+#define swiotlb_adjust_seg(start, size) ((void)0)
+#endif
+
+#ifndef swiotlb_print_info
+#define swiotlb_print_info(bytes) \
+       printk(KERN_INFO "Placing %luMB software IO TLB between 0x%lx - " \
+              "0x%lx\n", bytes >> 20, \
+              virt_to_bus(io_tlb_start), virt_to_bus(io_tlb_end))
+#endif
+
 /*
  * Statically reserve bounce buffer space and initialize bounce buffer data
  * structures for the software IO TLB used to implement the DMA API.
  */
-void
-swiotlb_init_with_default_size (size_t default_size)
+void __init
+swiotlb_init_with_default_size(size_t default_size)
 {
-       unsigned long i;
+       unsigned long i, bytes;
 
        if (!io_tlb_nslabs) {
                io_tlb_nslabs = (default_size >> IO_TLB_SHIFT);
                io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
        }
+       swiotlb_adjust_size(io_tlb_nslabs);
+       swiotlb_adjust_size(io_tlb_overflow);
+
+       bytes = io_tlb_nslabs << IO_TLB_SHIFT;
 
        /*
         * Get IO TLB memory from the low pages
         */
-       io_tlb_start = alloc_bootmem_low_pages(io_tlb_nslabs * (1 << IO_TLB_SHIFT));
+       io_tlb_start = alloc_bootmem_low_pages(bytes);
        if (!io_tlb_start)
                panic("Cannot allocate SWIOTLB buffer");
-       io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT);
+       io_tlb_end = io_tlb_start + bytes;
 
        /*
         * Allocate and initialize the free list array.  This array is used
@@ -153,34 +188,45 @@ swiotlb_init_with_default_size (size_t default_size)
         * between io_tlb_start and io_tlb_end.
         */
        io_tlb_list = alloc_bootmem(io_tlb_nslabs * sizeof(int));
-       for (i = 0; i < io_tlb_nslabs; i++)
+       for (i = 0; i < io_tlb_nslabs; i++) {
+               if ( !(i % IO_TLB_SEGSIZE) )
+                       swiotlb_adjust_seg(io_tlb_start + (i << IO_TLB_SHIFT),
+                               IO_TLB_SEGSIZE << IO_TLB_SHIFT);
                io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
+       }
        io_tlb_index = 0;
-       io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(char *));
+       io_tlb_orig_addr = alloc_bootmem(io_tlb_nslabs * sizeof(io_tlb_addr_t));
 
        /*
         * Get the overflow emergency buffer
         */
        io_tlb_overflow_buffer = alloc_bootmem_low(io_tlb_overflow);
-       printk(KERN_INFO "Placing software IO TLB between 0x%lx - 0x%lx\n",
-              virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end));
+       if (!io_tlb_overflow_buffer)
+               panic("Cannot allocate SWIOTLB overflow buffer!\n");
+       swiotlb_adjust_seg(io_tlb_overflow_buffer, io_tlb_overflow);
+
+       swiotlb_print_info(bytes);
 }
+#ifndef __swiotlb_init_with_default_size
+#define __swiotlb_init_with_default_size swiotlb_init_with_default_size
+#endif
 
-void
-swiotlb_init (void)
+void __init
+swiotlb_init(void)
 {
-       swiotlb_init_with_default_size(64 * (1<<20));   /* default to 64MB */
+       __swiotlb_init_with_default_size(64 * (1<<20)); /* default to 64MB */
 }
 
+#ifdef SWIOTLB_ARCH_NEED_LATE_INIT
 /*
  * Systems with larger DMA zones (those that don't support ISA) can
  * initialize the swiotlb later using the slab allocator if needed.
  * This should be just like above, but with some error catching.
  */
 int
-swiotlb_late_init_with_default_size (size_t default_size)
+swiotlb_late_init_with_default_size(size_t default_size)
 {
-       unsigned long i, req_nslabs = io_tlb_nslabs;
+       unsigned long i, bytes, req_nslabs = io_tlb_nslabs;
        unsigned int order;
 
        if (!io_tlb_nslabs) {
@@ -191,8 +237,9 @@ swiotlb_late_init_with_default_size (size_t default_size)
        /*
         * Get IO TLB memory from the low pages
         */
-       order = get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT));
+       order = get_order(io_tlb_nslabs << IO_TLB_SHIFT);
        io_tlb_nslabs = SLABS_PER_PAGE << order;
+       bytes = io_tlb_nslabs << IO_TLB_SHIFT;
 
        while ((SLABS_PER_PAGE << order) > IO_TLB_MIN_SLABS) {
                io_tlb_start = (char *)__get_free_pages(GFP_DMA | __GFP_NOWARN,
@@ -205,13 +252,14 @@ swiotlb_late_init_with_default_size (size_t default_size)
        if (!io_tlb_start)
                goto cleanup1;
 
-       if (order != get_order(io_tlb_nslabs * (1 << IO_TLB_SHIFT))) {
+       if (order != get_order(bytes)) {
                printk(KERN_WARNING "Warning: only able to allocate %ld MB "
                       "for software IO TLB\n", (PAGE_SIZE << order) >> 20);
                io_tlb_nslabs = SLABS_PER_PAGE << order;
+               bytes = io_tlb_nslabs << IO_TLB_SHIFT;
        }
-       io_tlb_end = io_tlb_start + io_tlb_nslabs * (1 << IO_TLB_SHIFT);
-       memset(io_tlb_start, 0, io_tlb_nslabs * (1 << IO_TLB_SHIFT));
+       io_tlb_end = io_tlb_start + bytes;
+       memset(io_tlb_start, 0, bytes);
 
        /*
         * Allocate and initialize the free list array.  This array is used
@@ -227,12 +275,12 @@ swiotlb_late_init_with_default_size (size_t default_size)
                io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
        io_tlb_index = 0;
 
-       io_tlb_orig_addr = (unsigned char **)__get_free_pages(GFP_KERNEL,
-                                  get_order(io_tlb_nslabs * sizeof(char *)));
+       io_tlb_orig_addr = (io_tlb_addr_t *)__get_free_pages(GFP_KERNEL,
+                                  get_order(io_tlb_nslabs * sizeof(io_tlb_addr_t)));
        if (!io_tlb_orig_addr)
                goto cleanup3;
 
-       memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(char *));
+       memset(io_tlb_orig_addr, 0, io_tlb_nslabs * sizeof(io_tlb_addr_t));
 
        /*
         * Get the overflow emergency buffer
@@ -242,29 +290,29 @@ swiotlb_late_init_with_default_size (size_t default_size)
        if (!io_tlb_overflow_buffer)
                goto cleanup4;
 
-       printk(KERN_INFO "Placing %ldMB software IO TLB between 0x%lx - "
-              "0x%lx\n", (io_tlb_nslabs * (1 << IO_TLB_SHIFT)) >> 20,
-              virt_to_phys(io_tlb_start), virt_to_phys(io_tlb_end));
+       swiotlb_print_info(bytes);
 
        return 0;
 
 cleanup4:
-       free_pages((unsigned long)io_tlb_orig_addr, get_order(io_tlb_nslabs *
-                                                             sizeof(char *)));
+       free_pages((unsigned long)io_tlb_orig_addr,
+                  get_order(io_tlb_nslabs * sizeof(io_tlb_addr_t)));
        io_tlb_orig_addr = NULL;
 cleanup3:
-       free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs *
-                                                        sizeof(int)));
+       free_pages((unsigned long)io_tlb_list,
+                  get_order(io_tlb_nslabs * sizeof(int)));
        io_tlb_list = NULL;
-       io_tlb_end = NULL;
 cleanup2:
+       io_tlb_end = NULL;
        free_pages((unsigned long)io_tlb_start, order);
        io_tlb_start = NULL;
 cleanup1:
        io_tlb_nslabs = req_nslabs;
        return -ENOMEM;
 }
+#endif
 
+#ifndef SWIOTLB_ARCH_HAS_NEEDS_MAPPING
 static inline int
 address_needs_mapping(struct device *hwdev, dma_addr_t addr)
 {
@@ -275,11 +323,35 @@ address_needs_mapping(struct device *hwdev, dma_addr_t addr)
        return (addr & ~mask) != 0;
 }
 
+static inline int range_needs_mapping(const void *ptr, size_t size)
+{
+       return swiotlb_force;
+}
+
+static inline int order_needs_mapping(unsigned int order)
+{
+       return 0;
+}
+#endif
+
+static void
+__sync_single(io_tlb_addr_t buffer, char *dma_addr, size_t size, int dir)
+{
+#ifndef SWIOTLB_ARCH_HAS_SYNC_SINGLE
+       if (dir == DMA_TO_DEVICE)
+               memcpy(dma_addr, buffer, size);
+       else
+               memcpy(buffer, dma_addr, size);
+#else
+       __swiotlb_arch_sync_single(buffer, dma_addr, size, dir);
+#endif
+}
+
 /*
  * Allocates bounce buffer and returns its kernel virtual address.
  */
 static void *
-map_single(struct device *hwdev, char *buffer, size_t size, int dir)
+map_single(struct device *hwdev, io_tlb_addr_t buffer, size_t size, int dir)
 {
        unsigned long flags;
        char *dma_addr;
@@ -352,7 +424,7 @@ map_single(struct device *hwdev, char *buffer, size_t size, int dir)
         */
        io_tlb_orig_addr[index] = buffer;
        if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
-               memcpy(dma_addr, buffer, size);
+               __sync_single(buffer, dma_addr, size, DMA_TO_DEVICE);
 
        return dma_addr;
 }
@@ -366,17 +438,18 @@ unmap_single(struct device *hwdev, char *dma_addr, size_t size, int dir)
        unsigned long flags;
        int i, count, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
        int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
-       char *buffer = io_tlb_orig_addr[index];
+       io_tlb_addr_t buffer = io_tlb_orig_addr[index];
 
        /*
         * First, sync the memory before unmapping the entry
         */
-       if (buffer && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
+       if (!swiotlb_orig_addr_null(buffer)
+           && ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL)))
                /*
                 * bounce... copy the data back into the original buffer * and
                 * delete the bounce buffer.
                 */
-               memcpy(buffer, dma_addr, size);
+               __sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE);
 
        /*
         * Return the buffer to the free list by setting the corresponding
@@ -409,18 +482,18 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size,
            int dir, int target)
 {
        int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
-       char *buffer = io_tlb_orig_addr[index];
+       io_tlb_addr_t buffer = io_tlb_orig_addr[index];
 
        switch (target) {
        case SYNC_FOR_CPU:
                if (likely(dir == DMA_FROM_DEVICE || dir == DMA_BIDIRECTIONAL))
-                       memcpy(buffer, dma_addr, size);
+                       __sync_single(buffer, dma_addr, size, DMA_FROM_DEVICE);
                else
                        BUG_ON(dir != DMA_TO_DEVICE);
                break;
        case SYNC_FOR_DEVICE:
                if (likely(dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
-                       memcpy(dma_addr, buffer, size);
+                       __sync_single(buffer, dma_addr, size, DMA_TO_DEVICE);
                else
                        BUG_ON(dir != DMA_FROM_DEVICE);
                break;
@@ -429,11 +502,13 @@ sync_single(struct device *hwdev, char *dma_addr, size_t size,
        }
 }
 
+#ifdef SWIOTLB_ARCH_NEED_ALLOC
+
 void *
 swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                       dma_addr_t *dma_handle, gfp_t flags)
 {
-       unsigned long dev_addr;
+       dma_addr_t dev_addr;
        void *ret;
        int order = get_order(size);
 
@@ -444,8 +519,11 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
         */
        flags |= GFP_DMA;
 
-       ret = (void *)__get_free_pages(flags, order);
-       if (ret && address_needs_mapping(hwdev, virt_to_phys(ret))) {
+       if (!order_needs_mapping(order))
+               ret = (void *)__get_free_pages(flags, order);
+       else
+               ret = NULL;
+       if (ret && address_needs_mapping(hwdev, virt_to_bus(ret))) {
                /*
                 * The allocated memory isn't reachable by the device.
                 * Fall back on swiotlb_map_single().
@@ -465,22 +543,24 @@ swiotlb_alloc_coherent(struct device *hwdev, size_t size,
                if (swiotlb_dma_mapping_error(handle))
                        return NULL;
 
-               ret = phys_to_virt(handle);
+               ret = bus_to_virt(handle);
        }
 
        memset(ret, 0, size);
-       dev_addr = virt_to_phys(ret);
+       dev_addr = virt_to_bus(ret);
 
        /* Confirm address can be DMA'd by device */
        if (address_needs_mapping(hwdev, dev_addr)) {
-               printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016lx\n",
-                      (unsigned long long)*hwdev->dma_mask, dev_addr);
+               printk("hwdev DMA mask = 0x%016Lx, dev_addr = 0x%016Lx\n",
+                      (unsigned long long)*hwdev->dma_mask,
+                      (unsigned long long)dev_addr);
                panic("swiotlb_alloc_coherent: allocated memory is out of "
                      "range for device");
        }
        *dma_handle = dev_addr;
        return ret;
 }
+EXPORT_SYMBOL(swiotlb_alloc_coherent);
 
 void
 swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
@@ -493,6 +573,9 @@ swiotlb_free_coherent(struct device *hwdev, size_t size, void *vaddr,
                /* DMA_TO_DEVICE to avoid memcpy in unmap_single */
                swiotlb_unmap_single (hwdev, dma_handle, size, DMA_TO_DEVICE);
 }
+EXPORT_SYMBOL(swiotlb_free_coherent);
+
+#endif
 
 static void
 swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
@@ -504,7 +587,7 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
         * When the mapping is small enough return a static buffer to limit
         * the damage, or panic when the transfer is too big.
         */
-       printk(KERN_ERR "DMA: Out of SW-IOMMU space for %lu bytes at "
+       printk(KERN_ERR "DMA: Out of SW-IOMMU space for %zu bytes at "
               "device %s\n", size, dev ? dev->bus_id : "?");
 
        if (size > io_tlb_overflow && do_panic) {
@@ -525,7 +608,7 @@ swiotlb_full(struct device *dev, size_t size, int dir, int do_panic)
 dma_addr_t
 swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
 {
-       unsigned long dev_addr = virt_to_phys(ptr);
+       dma_addr_t dev_addr = virt_to_bus(ptr);
        void *map;
 
        BUG_ON(dir == DMA_NONE);
@@ -534,19 +617,20 @@ swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
         * we can safely return the device addr and not worry about bounce
         * buffering it.
         */
-       if (!address_needs_mapping(hwdev, dev_addr) && !swiotlb_force)
+       if (!range_needs_mapping(ptr, size)
+           && !address_needs_mapping(hwdev, dev_addr))
                return dev_addr;
 
        /*
         * Oh well, have to allocate and map a bounce buffer.
         */
-       map = map_single(hwdev, ptr, size, dir);
+       map = map_single(hwdev, ptr_to_io_tlb_addr(ptr), size, dir);
        if (!map) {
                swiotlb_full(hwdev, size, dir, 1);
                map = io_tlb_overflow_buffer;
        }
 
-       dev_addr = virt_to_phys(map);
+       dev_addr = virt_to_bus(map);
 
        /*
         * Ensure that the address returned is DMA'ble
@@ -557,25 +641,6 @@ swiotlb_map_single(struct device *hwdev, void *ptr, size_t size, int dir)
        return dev_addr;
 }
 
-/*
- * Since DMA is i-cache coherent, any (complete) pages that were written via
- * DMA can be marked as "clean" so that lazy_mmu_prot_update() doesn't have to
- * flush them when they get mapped into an executable vm-area.
- */
-static void
-mark_clean(void *addr, size_t size)
-{
-       unsigned long pg_addr, end;
-
-       pg_addr = PAGE_ALIGN((unsigned long) addr);
-       end = (unsigned long) addr + size;
-       while (pg_addr + PAGE_SIZE <= end) {
-               struct page *page = virt_to_page(pg_addr);
-               set_bit(PG_arch_1, &page->flags);
-               pg_addr += PAGE_SIZE;
-       }
-}
-
 /*
  * Unmap a single streaming mode DMA translation.  The dma_addr and size must
  * match what was provided for in a previous swiotlb_map_single call.  All
@@ -588,13 +653,13 @@ void
 swiotlb_unmap_single(struct device *hwdev, dma_addr_t dev_addr, size_t size,
                     int dir)
 {
-       char *dma_addr = phys_to_virt(dev_addr);
+       char *dma_addr = bus_to_virt(dev_addr);
 
        BUG_ON(dir == DMA_NONE);
        if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
                unmap_single(hwdev, dma_addr, size, dir);
        else if (dir == DMA_FROM_DEVICE)
-               mark_clean(dma_addr, size);
+               dma_mark_clean(dma_addr, size);
 }
 
 /*
@@ -611,13 +676,13 @@ static inline void
 swiotlb_sync_single(struct device *hwdev, dma_addr_t dev_addr,
                    size_t size, int dir, int target)
 {
-       char *dma_addr = phys_to_virt(dev_addr);
+       char *dma_addr = bus_to_virt(dev_addr);
 
        BUG_ON(dir == DMA_NONE);
        if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
                sync_single(hwdev, dma_addr, size, dir, target);
        else if (dir == DMA_FROM_DEVICE)
-               mark_clean(dma_addr, size);
+               dma_mark_clean(dma_addr, size);
 }
 
 void
@@ -642,13 +707,13 @@ swiotlb_sync_single_range(struct device *hwdev, dma_addr_t dev_addr,
                          unsigned long offset, size_t size,
                          int dir, int target)
 {
-       char *dma_addr = phys_to_virt(dev_addr) + offset;
+       char *dma_addr = bus_to_virt(dev_addr) + offset;
 
        BUG_ON(dir == DMA_NONE);
        if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
                sync_single(hwdev, dma_addr, size, dir, target);
        else if (dir == DMA_FROM_DEVICE)
-               mark_clean(dma_addr, size);
+               dma_mark_clean(dma_addr, size);
 }
 
 void
@@ -687,18 +752,16 @@ int
 swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems,
               int dir)
 {
-       void *addr;
-       unsigned long dev_addr;
+       dma_addr_t dev_addr;
        int i;
 
        BUG_ON(dir == DMA_NONE);
 
        for (i = 0; i < nelems; i++, sg++) {
-               addr = SG_ENT_VIRT_ADDRESS(sg);
-               dev_addr = virt_to_phys(addr);
-               if (swiotlb_force || address_needs_mapping(hwdev, dev_addr)) {
-                       void *map = map_single(hwdev, addr, sg->length, dir);
-                       sg->dma_address = virt_to_bus(map);
+               dev_addr = SG_ENT_PHYS_ADDRESS(sg);
+               if (range_needs_mapping(SG_ENT_VIRT_ADDRESS(sg), sg->length)
+                   || address_needs_mapping(hwdev, dev_addr)) {
+                       void *map = map_single(hwdev, sg_to_io_tlb_addr(sg), sg->length, dir);
                        if (!map) {
                                /* Don't panic here, we expect map_sg users
                                   to do proper error handling. */
@@ -707,6 +770,7 @@ swiotlb_map_sg(struct device *hwdev, struct scatterlist *sg, int nelems,
                                sg[0].dma_length = 0;
                                return 0;
                        }
+                       sg->dma_address = virt_to_bus(map);
                } else
                        sg->dma_address = dev_addr;
                sg->dma_length = sg->length;
@@ -728,9 +792,10 @@ swiotlb_unmap_sg(struct device *hwdev, struct scatterlist *sg, int nelems,
 
        for (i = 0; i < nelems; i++, sg++)
                if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
-                       unmap_single(hwdev, (void *) phys_to_virt(sg->dma_address), sg->dma_length, dir);
+                       unmap_single(hwdev, bus_to_virt(sg->dma_address),
+                                    sg->dma_length, dir);
                else if (dir == DMA_FROM_DEVICE)
-                       mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
+                       dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
 }
 
 /*
@@ -750,8 +815,10 @@ swiotlb_sync_sg(struct device *hwdev, struct scatterlist *sg,
 
        for (i = 0; i < nelems; i++, sg++)
                if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
-                       sync_single(hwdev, (void *) sg->dma_address,
+                       sync_single(hwdev, bus_to_virt(sg->dma_address),
                                    sg->dma_length, dir, target);
+               else if (dir == DMA_FROM_DEVICE)
+                       dma_mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
 }
 
 void
@@ -768,10 +835,48 @@ swiotlb_sync_sg_for_device(struct device *hwdev, struct scatterlist *sg,
        swiotlb_sync_sg(hwdev, sg, nelems, dir, SYNC_FOR_DEVICE);
 }
 
+#ifdef SWIOTLB_ARCH_NEED_MAP_PAGE
+
+dma_addr_t
+swiotlb_map_page(struct device *hwdev, struct page *page,
+                unsigned long offset, size_t size,
+                enum dma_data_direction direction)
+{
+       dma_addr_t dev_addr;
+       char *map;
+
+       dev_addr = page_to_bus(page) + offset;
+       if (address_needs_mapping(hwdev, dev_addr)) {
+               map = map_single(hwdev, page_to_io_tlb_addr(page, offset), size, direction);
+               if (!map) {
+                       swiotlb_full(hwdev, size, direction, 1);
+                       map = io_tlb_overflow_buffer;
+               }
+               dev_addr = virt_to_bus(map);
+       }
+
+       return dev_addr;
+}
+
+void
+swiotlb_unmap_page(struct device *hwdev, dma_addr_t dev_addr,
+                  size_t size, enum dma_data_direction direction)
+{
+       char *dma_addr = bus_to_virt(dev_addr);
+
+       BUG_ON(direction == DMA_NONE);
+       if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
+               unmap_single(hwdev, dma_addr, size, direction);
+       else if (direction == DMA_FROM_DEVICE)
+               dma_mark_clean(dma_addr, size);
+}
+
+#endif
+
 int
 swiotlb_dma_mapping_error(dma_addr_t dma_addr)
 {
-       return (dma_addr == virt_to_phys(io_tlb_overflow_buffer));
+       return (dma_addr == virt_to_bus(io_tlb_overflow_buffer));
 }
 
 /*
@@ -780,10 +885,13 @@ swiotlb_dma_mapping_error(dma_addr_t dma_addr)
  * during bus mastering, then you would pass 0x00ffffff as the mask to
  * this function.
  */
+#ifndef __swiotlb_dma_supported
+#define __swiotlb_dma_supported(hwdev, mask) (virt_to_bus(io_tlb_end - 1) <= (mask))
+#endif
 int
-swiotlb_dma_supported (struct device *hwdev, u64 mask)
+swiotlb_dma_supported(struct device *hwdev, u64 mask)
 {
-       return (virt_to_phys (io_tlb_end) - 1) <= mask;
+       return __swiotlb_dma_supported(hwdev, mask);
 }
 
 EXPORT_SYMBOL(swiotlb_init);
@@ -798,6 +906,4 @@ EXPORT_SYMBOL_GPL(swiotlb_sync_single_range_for_device);
 EXPORT_SYMBOL(swiotlb_sync_sg_for_cpu);
 EXPORT_SYMBOL(swiotlb_sync_sg_for_device);
 EXPORT_SYMBOL(swiotlb_dma_mapping_error);
-EXPORT_SYMBOL(swiotlb_alloc_coherent);
-EXPORT_SYMBOL(swiotlb_free_coherent);
 EXPORT_SYMBOL(swiotlb_dma_supported);
index 55bb263..2b7c2c7 100644 (file)
@@ -286,7 +286,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
        kobject_init(&p->kobj);
        kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR);
        p->kobj.ktype = &brport_ktype;
-       p->kobj.parent = &(dev->class_dev.kobj);
+       p->kobj.parent = &(dev->dev.kobj);
        p->kobj.kset = NULL;
 
        return p;
index de9d1a9..ce10464 100644 (file)
 
 #include "br_private.h"
 
-#define to_class_dev(obj) container_of(obj,struct class_device,kobj)
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
+#define to_dev(obj)    container_of(obj, struct device, kobj)
 #define to_bridge(cd)  ((struct net_bridge *)(to_net_dev(cd)->priv))
 
 /*
  * Common code for storing bridge parameters.
  */
-static ssize_t store_bridge_parm(struct class_device *cd,
+static ssize_t store_bridge_parm(struct device *d,
                                 const char *buf, size_t len,
                                 void (*set)(struct net_bridge *, unsigned long))
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        char *endp;
        unsigned long val;
 
@@ -50,9 +49,10 @@ static ssize_t store_bridge_parm(struct class_device *cd,
 }
 
 
-static ssize_t show_forward_delay(struct class_device *cd, char *buf)
+static ssize_t show_forward_delay(struct device *d,
+                                 struct device_attribute *attr, char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->forward_delay));
 }
 
@@ -64,18 +64,20 @@ static void set_forward_delay(struct net_bridge *br, unsigned long val)
                br->bridge_forward_delay = delay;
 }
 
-static ssize_t store_forward_delay(struct class_device *cd, const char *buf,
-                                  size_t len)
+static ssize_t store_forward_delay(struct device *d,
+                                  struct device_attribute *attr,
+                                  const char *buf, size_t len)
 {
-       return store_bridge_parm(cd, buf, len, set_forward_delay);
+       return store_bridge_parm(d, buf, len, set_forward_delay);
 }
-static CLASS_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
-                        show_forward_delay, store_forward_delay);
+static DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
+                  show_forward_delay, store_forward_delay);
 
-static ssize_t show_hello_time(struct class_device *cd, char *buf)
+static ssize_t show_hello_time(struct device *d, struct device_attribute *attr,
+                              char *buf)
 {
        return sprintf(buf, "%lu\n",
-                      jiffies_to_clock_t(to_bridge(cd)->hello_time));
+                      jiffies_to_clock_t(to_bridge(d)->hello_time));
 }
 
 static void set_hello_time(struct net_bridge *br, unsigned long val)
@@ -86,19 +88,20 @@ static void set_hello_time(struct net_bridge *br, unsigned long val)
                br->bridge_hello_time = t;
 }
 
-static ssize_t store_hello_time(struct class_device *cd, const char *buf,
+static ssize_t store_hello_time(struct device *d,
+                               struct device_attribute *attr, const char *buf,
                                size_t len)
 {
-       return store_bridge_parm(cd, buf, len, set_hello_time);
+       return store_bridge_parm(d, buf, len, set_hello_time);
 }
+static DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
+                  store_hello_time);
 
-static CLASS_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
-                        store_hello_time);
-
-static ssize_t show_max_age(struct class_device *cd, char *buf)
+static ssize_t show_max_age(struct device *d, struct device_attribute *attr,
+                           char *buf)
 {
        return sprintf(buf, "%lu\n",
-                      jiffies_to_clock_t(to_bridge(cd)->max_age));
+                      jiffies_to_clock_t(to_bridge(d)->max_age));
 }
 
 static void set_max_age(struct net_bridge *br, unsigned long val)
@@ -109,18 +112,17 @@ static void set_max_age(struct net_bridge *br, unsigned long val)
                br->bridge_max_age = t;
 }
 
-static ssize_t store_max_age(struct class_device *cd, const char *buf,
-                               size_t len)
+static ssize_t store_max_age(struct device *d, struct device_attribute *attr,
+                            const char *buf, size_t len)
 {
-       return store_bridge_parm(cd, buf, len, set_max_age);
+       return store_bridge_parm(d, buf, len, set_max_age);
 }
+static DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
 
-static CLASS_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age,
-                        store_max_age);
-
-static ssize_t show_ageing_time(struct class_device *cd, char *buf)
+static ssize_t show_ageing_time(struct device *d,
+                               struct device_attribute *attr, char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%lu\n", jiffies_to_clock_t(br->ageing_time));
 }
 
@@ -129,17 +131,19 @@ static void set_ageing_time(struct net_bridge *br, unsigned long val)
        br->ageing_time = clock_t_to_jiffies(val);
 }
 
-static ssize_t store_ageing_time(struct class_device *cd, const char *buf,
-                                size_t len)
+static ssize_t store_ageing_time(struct device *d,
+                                struct device_attribute *attr,
+                                const char *buf, size_t len)
 {
-       return store_bridge_parm(cd, buf, len, set_ageing_time);
+       return store_bridge_parm(d, buf, len, set_ageing_time);
 }
+static DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
+                  store_ageing_time);
 
-static CLASS_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
-                        store_ageing_time);
-static ssize_t show_stp_state(struct class_device *cd, char *buf)
+static ssize_t show_stp_state(struct device *d,
+                             struct device_attribute *attr, char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%d\n", br->stp_enabled);
 }
 
@@ -148,18 +152,19 @@ static void set_stp_state(struct net_bridge *br, unsigned long val)
        br->stp_enabled = val;
 }
 
-static ssize_t store_stp_state(struct class_device *cd,
-                              const char *buf, size_t len)
+static ssize_t store_stp_state(struct device *d,
+                              struct device_attribute *attr, const char *buf,
+                              size_t len)
 {
-       return store_bridge_parm(cd, buf, len, set_stp_state);
+       return store_bridge_parm(d, buf, len, set_stp_state);
 }
+static DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
+                  store_stp_state);
 
-static CLASS_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
-                        store_stp_state);
-
-static ssize_t show_priority(struct class_device *cd, char *buf)
+static ssize_t show_priority(struct device *d, struct device_attribute *attr,
+                            char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%d\n",
                       (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]);
 }
@@ -169,92 +174,107 @@ static void set_priority(struct net_bridge *br, unsigned long val)
        br_stp_set_bridge_priority(br, (u16) val);
 }
 
-static ssize_t store_priority(struct class_device *cd,
+static ssize_t store_priority(struct device *d, struct device_attribute *attr,
                               const char *buf, size_t len)
 {
-       return store_bridge_parm(cd, buf, len, set_priority);
+       return store_bridge_parm(d, buf, len, set_priority);
 }
-static CLASS_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority,
-                        store_priority);
+static DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
 
-static ssize_t show_root_id(struct class_device *cd, char *buf)
+static ssize_t show_root_id(struct device *d, struct device_attribute *attr,
+                           char *buf)
 {
-       return br_show_bridge_id(buf, &to_bridge(cd)->designated_root);
+       return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
 }
-static CLASS_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
+static DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
 
-static ssize_t show_bridge_id(struct class_device *cd, char *buf)
+static ssize_t show_bridge_id(struct device *d, struct device_attribute *attr,
+                             char *buf)
 {
-       return br_show_bridge_id(buf, &to_bridge(cd)->bridge_id);
+       return br_show_bridge_id(buf, &to_bridge(d)->bridge_id);
 }
-static CLASS_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
+static DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
 
-static ssize_t show_root_port(struct class_device *cd, char *buf)
+static ssize_t show_root_port(struct device *d, struct device_attribute *attr,
+                             char *buf)
 {
-       return sprintf(buf, "%d\n", to_bridge(cd)->root_port);
+       return sprintf(buf, "%d\n", to_bridge(d)->root_port);
 }
-static CLASS_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
+static DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
 
-static ssize_t show_root_path_cost(struct class_device *cd, char *buf)
+static ssize_t show_root_path_cost(struct device *d,
+                                  struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "%d\n", to_bridge(cd)->root_path_cost);
+       return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
 }
-static CLASS_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
+static DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
 
-static ssize_t show_topology_change(struct class_device *cd, char *buf)
+static ssize_t show_topology_change(struct device *d,
+                                   struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "%d\n", to_bridge(cd)->topology_change);
+       return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
 }
-static CLASS_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
+static DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
 
-static ssize_t show_topology_change_detected(struct class_device *cd, char *buf)
+static ssize_t show_topology_change_detected(struct device *d,
+                                            struct device_attribute *attr,
+                                            char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%d\n", br->topology_change_detected);
 }
-static CLASS_DEVICE_ATTR(topology_change_detected, S_IRUGO, show_topology_change_detected, NULL);
+static DEVICE_ATTR(topology_change_detected, S_IRUGO,
+                  show_topology_change_detected, NULL);
 
-static ssize_t show_hello_timer(struct class_device *cd, char *buf)
+static ssize_t show_hello_timer(struct device *d,
+                               struct device_attribute *attr, char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%ld\n", br_timer_value(&br->hello_timer));
 }
-static CLASS_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
+static DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
 
-static ssize_t show_tcn_timer(struct class_device *cd, char *buf)
+static ssize_t show_tcn_timer(struct device *d, struct device_attribute *attr,
+                             char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%ld\n", br_timer_value(&br->tcn_timer));
 }
-static CLASS_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
+static DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
 
-static ssize_t show_topology_change_timer(struct class_device *cd, char *buf)
+static ssize_t show_topology_change_timer(struct device *d,
+                                         struct device_attribute *attr,
+                                         char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%ld\n", br_timer_value(&br->topology_change_timer));
 }
-static CLASS_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer, NULL);
+static DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
+                  NULL);
 
-static ssize_t show_gc_timer(struct class_device *cd, char *buf)
+static ssize_t show_gc_timer(struct device *d, struct device_attribute *attr,
+                            char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%ld\n", br_timer_value(&br->gc_timer));
 }
-static CLASS_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
+static DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
 
-static ssize_t show_group_addr(struct class_device *cd, char *buf)
+static ssize_t show_group_addr(struct device *d,
+                              struct device_attribute *attr, char *buf)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        return sprintf(buf, "%x:%x:%x:%x:%x:%x\n",
                       br->group_addr[0], br->group_addr[1],
                       br->group_addr[2], br->group_addr[3],
                       br->group_addr[4], br->group_addr[5]);
 }
 
-static ssize_t store_group_addr(struct class_device *cd, const char *buf,
-                                   size_t len)
+static ssize_t store_group_addr(struct device *d,
+                               struct device_attribute *attr,
+                               const char *buf, size_t len)
 {
-       struct net_bridge *br = to_bridge(cd);
+       struct net_bridge *br = to_bridge(d);
        unsigned new_addr[6];
        int i;
 
@@ -286,28 +306,28 @@ static ssize_t store_group_addr(struct class_device *cd, const char *buf,
        return len;
 }
 
-static CLASS_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
-                        show_group_addr, store_group_addr);
+static DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
+                  show_group_addr, store_group_addr);
 
 
 static struct attribute *bridge_attrs[] = {
-       &class_device_attr_forward_delay.attr,
-       &class_device_attr_hello_time.attr,
-       &class_device_attr_max_age.attr,
-       &class_device_attr_ageing_time.attr,
-       &class_device_attr_stp_state.attr,
-       &class_device_attr_priority.attr,
-       &class_device_attr_bridge_id.attr,
-       &class_device_attr_root_id.attr,
-       &class_device_attr_root_path_cost.attr,
-       &class_device_attr_root_port.attr,
-       &class_device_attr_topology_change.attr,
-       &class_device_attr_topology_change_detected.attr,
-       &class_device_attr_hello_timer.attr,
-       &class_device_attr_tcn_timer.attr,
-       &class_device_attr_topology_change_timer.attr,
-       &class_device_attr_gc_timer.attr,
-       &class_device_attr_group_addr.attr,
+       &dev_attr_forward_delay.attr,
+       &dev_attr_hello_time.attr,
+       &dev_attr_max_age.attr,
+       &dev_attr_ageing_time.attr,
+       &dev_attr_stp_state.attr,
+       &dev_attr_priority.attr,
+       &dev_attr_bridge_id.attr,
+       &dev_attr_root_id.attr,
+       &dev_attr_root_path_cost.attr,
+       &dev_attr_root_port.attr,
+       &dev_attr_topology_change.attr,
+       &dev_attr_topology_change_detected.attr,
+       &dev_attr_hello_timer.attr,
+       &dev_attr_tcn_timer.attr,
+       &dev_attr_topology_change_timer.attr,
+       &dev_attr_gc_timer.attr,
+       &dev_attr_group_addr.attr,
        NULL
 };
 
@@ -325,8 +345,8 @@ static struct attribute_group bridge_group = {
 static ssize_t brforward_read(struct kobject *kobj, char *buf,
                           loff_t off, size_t count)
 {
-       struct class_device *cdev = to_class_dev(kobj);
-       struct net_bridge *br = to_bridge(cdev);
+       struct device *dev = to_dev(kobj);
+       struct net_bridge *br = to_bridge(dev);
        int n;
 
        /* must read whole records */
@@ -363,7 +383,7 @@ static struct bin_attribute bridge_forward = {
  */
 int br_sysfs_addbr(struct net_device *dev)
 {
-       struct kobject *brobj = &dev->class_dev.kobj;
+       struct kobject *brobj = &dev->dev.kobj;
        struct net_bridge *br = netdev_priv(dev);
        int err;
 
@@ -395,9 +415,9 @@ int br_sysfs_addbr(struct net_device *dev)
        }
        return 0;
  out3:
-       sysfs_remove_bin_file(&dev->class_dev.kobj, &bridge_forward);
+       sysfs_remove_bin_file(&dev->dev.kobj, &bridge_forward);
  out2:
-       sysfs_remove_group(&dev->class_dev.kobj, &bridge_group);
+       sysfs_remove_group(&dev->dev.kobj, &bridge_group);
  out1:
        return err;
 
@@ -405,7 +425,7 @@ int br_sysfs_addbr(struct net_device *dev)
 
 void br_sysfs_delbr(struct net_device *dev)
 {
-       struct kobject *kobj = &dev->class_dev.kobj;
+       struct kobject *kobj = &dev->dev.kobj;
        struct net_bridge *br = netdev_priv(dev);
 
        kobject_unregister(&br->ifobj);
index c51c9e4..0bc2aef 100644 (file)
@@ -211,7 +211,7 @@ int br_sysfs_addif(struct net_bridge_port *p)
        struct brport_attribute **a;
        int err;
 
-       err = sysfs_create_link(&p->kobj, &br->dev->class_dev.kobj, 
+       err = sysfs_create_link(&p->kobj, &br->dev->dev.kobj,
                                SYSFS_BRIDGE_PORT_LINK);
        if (err)
                goto out2;
index e660cb5..455d589 100644 (file)
@@ -751,7 +751,7 @@ int dev_change_name(struct net_device *dev, char *newname)
        else
                strlcpy(dev->name, newname, IFNAMSIZ);
 
-       err = class_device_rename(&dev->class_dev, dev->name);
+       err = device_rename(&dev->dev, dev->name);
        if (!err) {
                hlist_del(&dev->name_hlist);
                hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
@@ -3221,8 +3221,8 @@ void free_netdev(struct net_device *dev)
        BUG_ON(dev->reg_state != NETREG_UNREGISTERED);
        dev->reg_state = NETREG_RELEASED;
 
-       /* will free via class release */
-       class_device_put(&dev->class_dev);
+       /* will free via device release */
+       put_device(&dev->dev);
 #else
        kfree((char *)dev - dev->padded);
 #endif
index f47f319..44db095 100644 (file)
@@ -18,9 +18,6 @@
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
 
-#define to_class_dev(obj) container_of(obj,struct class_device,kobj)
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
-
 static const char fmt_hex[] = "%#x\n";
 static const char fmt_long_hex[] = "%#lx\n";
 static const char fmt_dec[] = "%d\n";
@@ -32,10 +29,11 @@ static inline int dev_isalive(const struct net_device *dev)
 }
 
 /* use same locking rules as GIF* ioctl's */
-static ssize_t netdev_show(const struct class_device *cd, char *buf,
+static ssize_t netdev_show(const struct device *dev,
+                          struct device_attribute *attr, char *buf,
                           ssize_t (*format)(const struct net_device *, char *))
 {
-       struct net_device *net = to_net_dev(cd);
+       struct net_device *net = to_net_dev(dev);
        ssize_t ret = -EINVAL;
 
        read_lock(&dev_base_lock);
@@ -52,14 +50,15 @@ static ssize_t format_##field(const struct net_device *net, char *buf)      \
 {                                                                      \
        return sprintf(buf, format_string, net->field);                 \
 }                                                                      \
-static ssize_t show_##field(struct class_device *cd, char *buf)                \
+static ssize_t show_##field(struct device *dev,                                \
+                           struct device_attribute *attr, char *buf)   \
 {                                                                      \
-       return netdev_show(cd, buf, format_##field);                    \
+       return netdev_show(dev, attr, buf, format_##field);             \
 }
 
 
 /* use same locking and permission rules as SIF* ioctl's */
-static ssize_t netdev_store(struct class_device *dev,
+static ssize_t netdev_store(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t len,
                            int (*set)(struct net_device *, unsigned long))
 {
@@ -104,7 +103,8 @@ static ssize_t format_addr(char *buf, const unsigned char *addr, int len)
        return cp - buf;
 }
 
-static ssize_t show_address(struct class_device *dev, char *buf)
+static ssize_t show_address(struct device *dev, struct device_attribute *attr,
+                           char *buf)
 {
        struct net_device *net = to_net_dev(dev);
        ssize_t ret = -EINVAL;
@@ -116,7 +116,8 @@ static ssize_t show_address(struct class_device *dev, char *buf)
        return ret;
 }
 
-static ssize_t show_broadcast(struct class_device *dev, char *buf)
+static ssize_t show_broadcast(struct device *dev,
+                           struct device_attribute *attr, char *buf)
 {
        struct net_device *net = to_net_dev(dev);
        if (dev_isalive(net))
@@ -124,7 +125,8 @@ static ssize_t show_broadcast(struct class_device *dev, char *buf)
        return -EINVAL;
 }
 
-static ssize_t show_carrier(struct class_device *dev, char *buf)
+static ssize_t show_carrier(struct device *dev,
+                           struct device_attribute *attr, char *buf)
 {
        struct net_device *netdev = to_net_dev(dev);
        if (netif_running(netdev)) {
@@ -133,7 +135,8 @@ static ssize_t show_carrier(struct class_device *dev, char *buf)
        return -EINVAL;
 }
 
-static ssize_t show_dormant(struct class_device *dev, char *buf)
+static ssize_t show_dormant(struct device *dev,
+                           struct device_attribute *attr, char *buf)
 {
        struct net_device *netdev = to_net_dev(dev);
 
@@ -153,7 +156,8 @@ static const char *operstates[] = {
        "up"
 };
 
-static ssize_t show_operstate(struct class_device *dev, char *buf)
+static ssize_t show_operstate(struct device *dev,
+                             struct device_attribute *attr, char *buf)
 {
        const struct net_device *netdev = to_net_dev(dev);
        unsigned char operstate;
@@ -178,9 +182,10 @@ static int change_mtu(struct net_device *net, unsigned long new_mtu)
        return dev_set_mtu(net, (int) new_mtu);
 }
 
-static ssize_t store_mtu(struct class_device *dev, const char *buf, size_t len)
+static ssize_t store_mtu(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t len)
 {
-       return netdev_store(dev, buf, len, change_mtu);
+       return netdev_store(dev, attr, buf, len, change_mtu);
 }
 
 NETDEVICE_SHOW(flags, fmt_hex);
@@ -190,9 +195,10 @@ static int change_flags(struct net_device *net, unsigned long new_flags)
        return dev_change_flags(net, (unsigned) new_flags);
 }
 
-static ssize_t store_flags(struct class_device *dev, const char *buf, size_t len)
+static ssize_t store_flags(struct device *dev, struct device_attribute *attr,
+                          const char *buf, size_t len)
 {
-       return netdev_store(dev, buf, len, change_flags);
+       return netdev_store(dev, attr, buf, len, change_flags);
 }
 
 NETDEVICE_SHOW(tx_queue_len, fmt_ulong);
@@ -203,9 +209,11 @@ static int change_tx_queue_len(struct net_device *net, unsigned long new_len)
        return 0;
 }
 
-static ssize_t store_tx_queue_len(struct class_device *dev, const char *buf, size_t len)
+static ssize_t store_tx_queue_len(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t len)
 {
-       return netdev_store(dev, buf, len, change_tx_queue_len);
+       return netdev_store(dev, attr, buf, len, change_tx_queue_len);
 }
 
 NETDEVICE_SHOW(weight, fmt_dec);
@@ -216,12 +224,13 @@ static int change_weight(struct net_device *net, unsigned long new_weight)
        return 0;
 }
 
-static ssize_t store_weight(struct class_device *dev, const char *buf, size_t len)
+static ssize_t store_weight(struct device *dev, struct device_attribute *attr,
+                           const char *buf, size_t len)
 {
-       return netdev_store(dev, buf, len, change_weight);
+       return netdev_store(dev, attr, buf, len, change_weight);
 }
 
-static struct class_device_attribute net_class_attributes[] = {
+static struct device_attribute net_class_attributes[] = {
        __ATTR(addr_len, S_IRUGO, show_addr_len, NULL),
        __ATTR(iflink, S_IRUGO, show_iflink, NULL),
        __ATTR(ifindex, S_IRUGO, show_ifindex, NULL),
@@ -242,10 +251,11 @@ static struct class_device_attribute net_class_attributes[] = {
 };
 
 /* Show a given an attribute in the statistics group */
-static ssize_t netstat_show(const struct class_device *cd, char *buf, 
+static ssize_t netstat_show(const struct device *d,
+                           struct device_attribute *attr, char *buf,
                            unsigned long offset)
 {
-       struct net_device *dev = to_net_dev(cd);
+       struct net_device *dev = to_net_dev(d);
        struct net_device_stats *stats;
        ssize_t ret = -EINVAL;
 
@@ -265,12 +275,13 @@ static ssize_t netstat_show(const struct class_device *cd, char *buf,
 
 /* generate a read-only statistics attribute */
 #define NETSTAT_ENTRY(name)                                            \
-static ssize_t show_##name(struct class_device *cd, char *buf)                 \
+static ssize_t show_##name(struct device *d,                           \
+                          struct device_attribute *attr, char *buf)    \
 {                                                                      \
-       return netstat_show(cd, buf,                                    \
+       return netstat_show(d, attr, buf,                               \
                            offsetof(struct net_device_stats, name));   \
 }                                                                      \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
+static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
 
 NETSTAT_ENTRY(rx_packets);
 NETSTAT_ENTRY(tx_packets);
@@ -297,29 +308,29 @@ NETSTAT_ENTRY(rx_compressed);
 NETSTAT_ENTRY(tx_compressed);
 
 static struct attribute *netstat_attrs[] = {
-       &class_device_attr_rx_packets.attr,
-       &class_device_attr_tx_packets.attr,
-       &class_device_attr_rx_bytes.attr,
-       &class_device_attr_tx_bytes.attr,
-       &class_device_attr_rx_errors.attr,
-       &class_device_attr_tx_errors.attr,
-       &class_device_attr_rx_dropped.attr,
-       &class_device_attr_tx_dropped.attr,
-       &class_device_attr_multicast.attr,
-       &class_device_attr_collisions.attr,
-       &class_device_attr_rx_length_errors.attr,
-       &class_device_attr_rx_over_errors.attr,
-       &class_device_attr_rx_crc_errors.attr,
-       &class_device_attr_rx_frame_errors.attr,
-       &class_device_attr_rx_fifo_errors.attr,
-       &class_device_attr_rx_missed_errors.attr,
-       &class_device_attr_tx_aborted_errors.attr,
-       &class_device_attr_tx_carrier_errors.attr,
-       &class_device_attr_tx_fifo_errors.attr,
-       &class_device_attr_tx_heartbeat_errors.attr,
-       &class_device_attr_tx_window_errors.attr,
-       &class_device_attr_rx_compressed.attr,
-       &class_device_attr_tx_compressed.attr,
+       &dev_attr_rx_packets.attr,
+       &dev_attr_tx_packets.attr,
+       &dev_attr_rx_bytes.attr,
+       &dev_attr_tx_bytes.attr,
+       &dev_attr_rx_errors.attr,
+       &dev_attr_tx_errors.attr,
+       &dev_attr_rx_dropped.attr,
+       &dev_attr_tx_dropped.attr,
+       &dev_attr_multicast.attr,
+       &dev_attr_collisions.attr,
+       &dev_attr_rx_length_errors.attr,
+       &dev_attr_rx_over_errors.attr,
+       &dev_attr_rx_crc_errors.attr,
+       &dev_attr_rx_frame_errors.attr,
+       &dev_attr_rx_fifo_errors.attr,
+       &dev_attr_rx_missed_errors.attr,
+       &dev_attr_tx_aborted_errors.attr,
+       &dev_attr_tx_carrier_errors.attr,
+       &dev_attr_tx_fifo_errors.attr,
+       &dev_attr_tx_heartbeat_errors.attr,
+       &dev_attr_tx_window_errors.attr,
+       &dev_attr_rx_compressed.attr,
+       &dev_attr_tx_compressed.attr,
        NULL
 };
 
@@ -331,11 +342,11 @@ static struct attribute_group netstat_group = {
 
 #ifdef WIRELESS_EXT
 /* helper function that does all the locking etc for wireless stats */
-static ssize_t wireless_show(struct class_device *cd, char *buf,
+static ssize_t wireless_show(struct device *d, char *buf,
                             ssize_t (*format)(const struct iw_statistics *,
                                               char *))
 {
-       struct net_device *dev = to_net_dev(cd);
+       struct net_device *dev = to_net_dev(d);
        const struct iw_statistics *iw = NULL;
        ssize_t ret = -EINVAL;
        
@@ -358,11 +369,12 @@ static ssize_t format_iw_##name(const struct iw_statistics *iw, char *buf) \
 {                                                                      \
        return sprintf(buf, format_string, iw->field);                  \
 }                                                                      \
-static ssize_t show_iw_##name(struct class_device *cd, char *buf)      \
+static ssize_t show_iw_##name(struct device *d,                                \
+                             struct device_attribute *attr, char *buf) \
 {                                                                      \
-       return wireless_show(cd, buf, format_iw_##name);                \
+       return wireless_show(d, buf, format_iw_##name);                 \
 }                                                                      \
-static CLASS_DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL)
+static DEVICE_ATTR(name, S_IRUGO, show_iw_##name, NULL)
 
 WIRELESS_SHOW(status, status, fmt_hex);
 WIRELESS_SHOW(link, qual.qual, fmt_dec);
@@ -376,16 +388,16 @@ WIRELESS_SHOW(retries, discard.retries, fmt_dec);
 WIRELESS_SHOW(beacon, miss.beacon, fmt_dec);
 
 static struct attribute *wireless_attrs[] = {
-       &class_device_attr_status.attr,
-       &class_device_attr_link.attr,
-       &class_device_attr_level.attr,
-       &class_device_attr_noise.attr,
-       &class_device_attr_nwid.attr,
-       &class_device_attr_crypt.attr,
-       &class_device_attr_fragment.attr,
-       &class_device_attr_retries.attr,
-       &class_device_attr_misc.attr,
-       &class_device_attr_beacon.attr,
+       &dev_attr_status.attr,
+       &dev_attr_link.attr,
+       &dev_attr_level.attr,
+       &dev_attr_noise.attr,
+       &dev_attr_nwid.attr,
+       &dev_attr_crypt.attr,
+       &dev_attr_fragment.attr,
+       &dev_attr_retries.attr,
+       &dev_attr_misc.attr,
+       &dev_attr_beacon.attr,
        NULL
 };
 
@@ -396,10 +408,10 @@ static struct attribute_group wireless_group = {
 #endif
 
 #ifdef CONFIG_HOTPLUG
-static int netdev_uevent(struct class_device *cd, char **envp,
+static int netdev_uevent(struct device *d, char **envp,
                         int num_envp, char *buf, int size)
 {
-       struct net_device *dev = to_net_dev(cd);
+       struct net_device *dev = to_net_dev(d);
        int i = 0;
        int n;
 
@@ -419,12 +431,11 @@ static int netdev_uevent(struct class_device *cd, char **envp,
 
 /*
  *     netdev_release -- destroy and free a dead device. 
- *     Called when last reference to class_device kobject is gone.
+ *     Called when last reference to device kobject is gone.
  */
-static void netdev_release(struct class_device *cd)
+static void netdev_release(struct device *d)
 {
-       struct net_device *dev 
-               = container_of(cd, struct net_device, class_dev);
+       struct net_device *dev = to_net_dev(d);
 
        BUG_ON(dev->reg_state != NETREG_RELEASED);
 
@@ -433,31 +444,31 @@ static void netdev_release(struct class_device *cd)
 
 static struct class net_class = {
        .name = "net",
-       .release = netdev_release,
-       .class_dev_attrs = net_class_attributes,
+       .dev_release = netdev_release,
+       .dev_attrs = net_class_attributes,
 #ifdef CONFIG_HOTPLUG
-       .uevent = netdev_uevent,
+       .dev_uevent = netdev_uevent,
 #endif
 };
 
 void netdev_unregister_sysfs(struct net_device * net)
 {
-       class_device_del(&(net->class_dev));
+       device_del(&(net->dev));
 }
 
 /* Create sysfs entries for network device. */
 int netdev_register_sysfs(struct net_device *net)
 {
-       struct class_device *class_dev = &(net->class_dev);
+       struct device *dev = &(net->dev);
        struct attribute_group **groups = net->sysfs_groups;
 
-       class_device_initialize(class_dev);
-       class_dev->class = &net_class;
-       class_dev->class_data = net;
-       class_dev->groups = groups;
+       device_initialize(dev);
+       dev->class = &net_class;
+       dev->platform_data = net;
+       dev->groups = groups;
 
        BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ);
-       strlcpy(class_dev->class_id, net->name, BUS_ID_SIZE);
+       strlcpy(dev->bus_id, net->name, BUS_ID_SIZE);
 
        if (net->get_stats)
                *groups++ = &netstat_group;
@@ -467,7 +478,7 @@ int netdev_register_sysfs(struct net_device *net)
                *groups++ = &wireless_group;
 #endif
 
-       return class_device_add(class_dev);
+       return device_add(dev);
 }
 
 int netdev_sysfs_init(void)
index de7801d..f3404ae 100644 (file)
@@ -268,7 +268,7 @@ nodata:
 struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
                unsigned int length, gfp_t gfp_mask)
 {
-       int node = dev->class_dev.dev ? dev_to_node(dev->class_dev.dev) : -1;
+       int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;
        struct sk_buff *skb;
 
        skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, node);
index fa2f7da..fb58e03 100644 (file)
@@ -265,6 +265,12 @@ ieee80211softmac_wx_get_rate(struct net_device *net_dev,
        int err = -EINVAL;
 
        spin_lock_irqsave(&mac->lock, flags);
+
+       if (unlikely(!mac->running)) {
+               err = -ENODEV;
+               goto out_unlock;
+       }
+
        switch (mac->txrates.default_rate) {
        case IEEE80211_CCK_RATE_1MB:
                data->bitrate.value = 1000000;
index f01f8c0..a1880e8 100644 (file)
@@ -1,7 +1,7 @@
 ####
 # kbuild: Generic definitions
 
-# Convinient variables
+# Convenient constants
 comma   := ,
 squote  := '
 empty   :=
@@ -56,76 +56,87 @@ endef
 # gcc support functions
 # See documentation in Documentation/kbuild/makefiles.txt
 
-# output directory for tests below
-TMPOUT := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/)
+# checker-shell
+# Usage: option = $(call checker-shell,$(CC)...-o $$OUT,option-ok,otherwise)
+# Exit code chooses option. $$OUT is safe location for needless output.
+define checker-shell
+$(shell set -e; \
+  DIR=$(KBUILD_EXTMOD); \
+  cd $${DIR:-$(objtree)}; \
+  OUT=$$PWD/.$$$$.null; \
+  if $(1) >/dev/null 2>&1; \
+    then echo "$(2)"; \
+    else echo "$(3)"; \
+  fi; \
+  rm -f $$OUT)
+endef
 
 # as-option
-# Usage: cflags-y += $(call as-option, -Wa$(comma)-isa=foo,)
-
-as-option = $(shell if $(CC) $(CFLAGS) $(1) -Wa,-Z -c -o /dev/null \
-            -xassembler /dev/null > /dev/null 2>&1; then echo "$(1)"; \
-            else echo "$(2)"; fi ;)
+# Usage: cflags-y += $(call as-option,-Wa$(comma)-isa=foo,)
+as-option = $(call checker-shell,\
+   $(CC) $(CFLAGS) $(1) -c -xassembler /dev/null -o $$OUT,$(1),$(2))
 
 # as-instr
-# Usage: cflags-y += $(call as-instr, instr, option1, option2)
-
-as-instr = $(shell if echo -e "$(1)" | \
-                     $(CC) $(AFLAGS) -c -xassembler - \
-                           -o $(TMPOUT)astest$$$$.out > /dev/null 2>&1; \
-                  then rm $(TMPOUT)astest$$$$.out; echo "$(2)"; \
-                  else echo "$(3)"; fi)
+# Usage: cflags-y += $(call as-instr,instr,option1,option2)
+as-instr = $(call checker-shell,\
+   printf "$(1)" | $(CC) $(AFLAGS) -c -xassembler -o $$OUT -,$(2),$(3))
 
 # cc-option
-# Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586)
-
-cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
-             > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
+# Usage: cflags-y += $(call cc-option,-march=winchip-c6,-march=i586)
+cc-option = $(call checker-shell,\
+   $(CC) $(CFLAGS) $(if $(3),$(3),$(1)) -S -xc /dev/null -o $$OUT,$(1),$(2))
 
 # cc-option-yn
-# Usage: flag := $(call cc-option-yn, -march=winchip-c6)
-cc-option-yn = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
-                > /dev/null 2>&1; then echo "y"; else echo "n"; fi;)
+# Usage: flag := $(call cc-option-yn,-march=winchip-c6)
+cc-option-yn = $(call cc-option,"y","n",$(1))
 
 # cc-option-align
 # Prefix align with either -falign or -malign
 cc-option-align = $(subst -functions=0,,\
-       $(call cc-option,-falign-functions=0,-malign-functions=0))
+   $(call cc-option,-falign-functions=0,-malign-functions=0))
 
 # cc-version
-# Usage gcc-ver := $(call cc-version, $(CC))
+# Usage gcc-ver := $(call cc-version,$(CC))
 cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh $(CC))
 
 # cc-ifversion
 # Usage:  EXTRA_CFLAGS += $(call cc-ifversion, -lt, 0402, -O1)
-cc-ifversion = $(shell if [ $(call cc-version, $(CC)) $(1) $(2) ]; then \
-                       echo $(3); fi;)
+cc-ifversion = $(shell [ $(call cc-version, $(CC)) $(1) $(2) ] && echo $(3))
 
 # ld-option
 # Usage: ldflags += $(call ld-option, -Wl$(comma)--hash-style=both)
-ld-option = $(shell if $(CC) $(1) -nostdlib -xc /dev/null \
-                            -o $(TMPOUT)ldtest$$$$.out > /dev/null 2>&1; \
-             then rm $(TMPOUT)ldtest$$$$.out; echo "$(1)"; \
-             else echo "$(2)"; fi)
+ld-option = $(call checker-shell,\
+   $(CC) $(1) -nostdlib -xc /dev/null -o $$OUT,$(1),$(2))
+
+######
 
-###
 # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
 # Usage:
 # $(Q)$(MAKE) $(build)=dir
 build := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.build obj
 
-# Prefix -I with $(srctree) if it is not an absolute path
-addtree = $(if $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1)
+# Prefix -I with $(srctree) if it is not an absolute path,
+# add original to the end
+addtree = $(if \
+       $(filter-out -I/%,$(1)),$(patsubst -I%,-I$(srctree)/%,$(1))) $(1)
+
 # Find all -I options and call addtree
-flags = $(foreach o,$($(1)),$(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o)))
+flags = $(foreach o,$($(1)),\
+       $(if $(filter -I%,$(o)),$(call addtree,$(o)),$(o)))
+
+# echo command.
+# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
+echo-cmd = $(if $($(quiet)cmd_$(1)),\
+       echo '  $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
 
-# If quiet is set, only print short version of command
+# printing commands
 cmd = @$(echo-cmd) $(cmd_$(1))
 
-# Add $(obj)/ for paths that is not absolute
+# Add $(obj)/ for paths that are not absolute
 objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
 
 ###
-# if_changed      - execute command if any prerequisite is newer than 
+# if_changed      - execute command if any prerequisite is newer than
 #                   target, or command line has changed
 # if_changed_dep  - as if_changed, but uses fixdep to reveal dependencies
 #                   including used config symbols
@@ -133,16 +144,12 @@ objectify = $(foreach o,$(1),$(if $(filter /%,$(o)),$(o),$(obj)/$(o)))
 # See Documentation/kbuild/makefiles.txt for more info
 
 ifneq ($(KBUILD_NOCMDDEP),1)
-# Check if both arguments has same arguments. Result in empty string if equal
+# Check if both arguments has same arguments. Result is empty string, if equal.
 # User may override this check using make KBUILD_NOCMDDEP=1
 arg-check = $(strip $(filter-out $(cmd_$(1)), $(cmd_$@)) \
                     $(filter-out $(cmd_$@),   $(cmd_$(1))) )
 endif
 
-# echo command. Short version is $(quiet) equals quiet, otherwise full command
-echo-cmd = $(if $($(quiet)cmd_$(1)), \
-       echo '  $(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
-
 # >'< substitution is for echo to work,
 # >$< substitution to preserve $ when reloading .cmd file
 # note: when using inline perl scripts [perl -e '...$$t=1;...']
@@ -153,15 +160,15 @@ make-cmd = $(subst \#,\\\#,$(subst $$,$$$$,$(call escsq,$(cmd_$(1)))))
 # PHONY targets skipped in both cases.
 any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
 
-# Execute command if command has changed or prerequisitei(s) are updated
+# Execute command if command has changed or prerequisite(s) are updated.
 #
 if_changed = $(if $(strip $(any-prereq) $(arg-check)),                       \
        @set -e;                                                             \
        $(echo-cmd) $(cmd_$(1));                                             \
        echo 'cmd_$@ := $(make-cmd)' > $(dot-target).cmd)
 
-# execute the command and also postprocess generated .d dependencies
-# file
+# Execute the command and also postprocess generated .d dependencies file.
+#
 if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ),                  \
        @set -e;                                                             \
        $(echo-cmd) $(cmd_$(1));                                             \
@@ -169,9 +176,10 @@ if_changed_dep = $(if $(strip $(any-prereq) $(arg-check) ),                  \
        rm -f $(depfile);                                                    \
        mv -f $(dot-target).tmp $(dot-target).cmd)
 
+# Will check if $(cmd_foo) changed, or any of the prerequisites changed,
+# and if so will execute $(rule_foo).
 # Usage: $(call if_changed_rule,foo)
-# will check if $(cmd_foo) changed, or any of the prequisites changed,
-# and if so will execute $(rule_foo)
+#
 if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ),                 \
        @set -e;                                                             \
        $(rule_$(1)))
index 4c723fd..43f75d6 100644 (file)
@@ -1,6 +1,6 @@
 #!/bin/bash
 # Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org>
-# Copyright (c) 2006           Sam Ravnborg <sam@ravnborg.org>
+# Copyright (C) 2006 Sam Ravnborg <sam@ravnborg.org>
 #
 # Released under the terms of the GNU GPL
 #
@@ -17,15 +17,15 @@ cat << EOF
 Usage:
 $0 [-o <file>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ...
        -o <file>      Create gzipped initramfs file named <file> using
-                      gen_init_cpio and gzip
+                      gen_init_cpio and gzip
        -u <uid>       User ID to map to user ID 0 (root).
-                      <uid> is only meaningful if <cpio_source>
-                      is a directory.
+                      <uid> is only meaningful if <cpio_source>
+                      is a directory.
        -g <gid>       Group ID to map to group ID 0 (root).
-                      <gid> is only meaningful if <cpio_source>
-                      is a directory.
+                      <gid> is only meaningful if <cpio_source>
+                      is a directory.
        <cpio_source>  File list or directory for cpio archive.
-                      If <cpio_source> is a .cpio file it will be used
+                      If <cpio_source> is a .cpio file it will be used
                       as direct input to initramfs.
        -d             Output the default cpio list.
 
@@ -36,6 +36,12 @@ to reset the root/group mapping.
 EOF
 }
 
+# awk style field access
+# $1 - field number; rest is argument string
+field() {
+       shift $1 ; echo $1
+}
+
 list_default_initramfs() {
        # echo usr/kinit/kinit
        :
@@ -119,22 +125,17 @@ parse() {
                        str="${ftype} ${name} ${location} ${str}"
                        ;;
                "nod")
-                       local dev_type=
-                       local maj=$(LC_ALL=C ls -l "${location}" | \
-                                       gawk '{sub(/,/, "", $5); print $5}')
-                       local min=$(LC_ALL=C ls -l "${location}" | \
-                                       gawk '{print $6}')
-
-                       if [ -b "${location}" ]; then
-                               dev_type="b"
-                       else
-                               dev_type="c"
-                       fi
-                       str="${ftype} ${name} ${str} ${dev_type} ${maj} ${min}"
+                       local dev=`LC_ALL=C ls -l "${location}"`
+                       local maj=`field 5 ${dev}`
+                       local min=`field 6 ${dev}`
+                       maj=${maj%,}
+
+                       [ -b "${location}" ] && dev="b" || dev="c"
+
+                       str="${ftype} ${name} ${str} ${dev} ${maj} ${min}"
                        ;;
                "slink")
-                       local target=$(LC_ALL=C ls -l "${location}" | \
-                                       gawk '{print $11}')
+                       local target=`field 11 $(LC_ALL=C ls -l "${location}")`
                        str="${ftype} ${name} ${target} ${str}"
                        ;;
                *)
index 34bd723..4fc80f2 100755 (executable)
@@ -1,31 +1,31 @@
-#!/bin/bash
+#!/bin/sh
 # A script to dump mixed source code & assembly
 # with correct relocations from System.map
-# Requires the following lines in Rules.make.
-# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) 
-#            William Stearns <wstearns@pobox.com>
+# Requires the following lines in makefile:
 #%.lst: %.c
 #      $(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(CFLAGS_$@) -g -c -o $*.o $<
-#      $(TOPDIR)/scripts/makelst $*.o $(TOPDIR)/System.map $(OBJDUMP)
+#      $(srctree)/scripts/makelst $*.o $(objtree)/System.map $(OBJDUMP)
 #
-#    Copyright (C) 2000 IBM Corporation
-#    Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) 
+# Copyright (C) 2000 IBM Corporation
+# Author(s): DJ Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
+#            William Stearns <wstearns@pobox.com>
 #
 
-t1=`$3 --syms $1 | grep .text | grep " F " | head -n 1`
+# awk style field access
+field() {
+  shift $1 ; echo $1
+}
+
+t1=`$3 --syms $1 | grep .text | grep -m1 " F "`
 if [ -n "$t1" ]; then
-  t2=`echo $t1 | gawk '{ print $6 }'`
+  t2=`field 6 $t1`
   if [ ! -r $2 ]; then
     echo "No System.map" >&2
-    t7=0
   else
     t3=`grep $t2 $2`
-    t4=`echo $t3 | gawk '{ print $1 }'`
-    t5=`echo $t1 | gawk '{ print $1 }'`
-    t6=`echo $t4 - $t5 | tr a-f A-F`
-    t7=`( echo  ibase=16 ; echo $t6 ) | bc`
+    t4=`field 1 $t3`
+    t5=`field 1 $t1`
+    t6=`printf "%lu" $((0x$t4 - 0x$t5))`
   fi
-else
-  t7=0
 fi
-$3 -r --source --adjust-vma=$t7 $1
+$3 -r --source --adjust-vma=${t6:-0} $1
index ac9326c..700400d 100644 (file)
@@ -188,6 +188,7 @@ static inline void key_alloc_serial(struct key *key)
 
        spin_lock(&key_serial_lock);
 
+attempt_insertion:
        parent = NULL;
        p = &key_serial_tree.rb_node;
 
@@ -202,39 +203,33 @@ static inline void key_alloc_serial(struct key *key)
                else
                        goto serial_exists;
        }
-       goto insert_here;
+
+       /* we've found a suitable hole - arrange for this key to occupy it */
+       rb_link_node(&key->serial_node, parent, p);
+       rb_insert_color(&key->serial_node, &key_serial_tree);
+
+       spin_unlock(&key_serial_lock);
+       return;
 
        /* we found a key with the proposed serial number - walk the tree from
         * that point looking for the next unused serial number */
 serial_exists:
        for (;;) {
                key->serial++;
-               if (key->serial < 2)
-                       key->serial = 2;
-
-               if (!rb_parent(parent))
-                       p = &key_serial_tree.rb_node;
-               else if (rb_parent(parent)->rb_left == parent)
-                       p = &(rb_parent(parent)->rb_left);
-               else
-                       p = &(rb_parent(parent)->rb_right);
+               if (key->serial < 3) {
+                       key->serial = 3;
+                       goto attempt_insertion;
+               }
 
                parent = rb_next(parent);
                if (!parent)
-                       break;
+                       goto attempt_insertion;
 
                xkey = rb_entry(parent, struct key, serial_node);
                if (key->serial < xkey->serial)
-                       goto insert_here;
+                       goto attempt_insertion;
        }
 
-       /* we've found a suitable hole - arrange for this key to occupy it */
-insert_here:
-       rb_link_node(&key->serial_node, parent, p);
-       rb_insert_color(&key->serial_node, &key_serial_tree);
-
-       spin_unlock(&key_serial_lock);
-
 } /* end key_alloc_serial() */
 
 /*****************************************************************************/